Web Worker — это способ запуска JavaScript в фоновых потоках. Рабочий поток может выполнять некоторые тяжелые работы, не мешая пользовательскому интерфейсу. В этой статье рассказывается, как загрузить WebAssembly и вызвать API Dynamsoft штрих-код JavaScript в веб-воркере.
Веб-воркер для WASM
Если вы пробовали пример Dynamsoft JavaScript Barcode SDK hello world, вы должны знать, что SDK построен на основе технологии WebAssembly, которая позволяет разрабатывать веб-приложение для чтения штрих-кода на стороне клиента на чистом JavaScript. Простой пример демонстрирует, как декодировать штрих-код из входного файла.
Однако в большинстве сценариев веб-считыватель штрих-кодов обеспечивает декодирование видеопотока с камеры в режиме реального времени. Принцип создания приложения камеры — не блокировать поток пользовательского интерфейса. Если вы вызываете API штрих-кода в основном потоке JavaScript, а API требует более 100 мс для декодирования штрих-кода, пользовательский интерфейс не может отображаться плавно. Вот почему нам нужно использовать веб-воркеров.
При использовании WebAssembly загрузка и компиляция файла wasm может занять много времени. Dynamsoft предоставляет две версии штрих-кода JavaScript, созданные с разными уровнями оптимизации, которые влияют на окончательный размер файла wasm и время инициализации. В worker.js добавьте следующий код:
functionbrowserRedirect() {vardeviceType;varsUserAgent = navigator.userAgent.toLowerCase();varbIsIpad = sUserAgent.match(/ipad/i) == "ipad";varbIsIphoneOs = sUserAgent.match(/iphone os/i) == "iphone os";varbIsMidp = sUserAgent.match(/midp/i) == "midp";varbIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4";varbIsUc = sUserAgent.match(/ucweb/i) == "ucweb";varbIsAndroid = sUserAgent.match(/android/i) == "android";varbIsCE = sUserAgent.match(/windows ce/i) == "windows ce";varbIsWM = sUserAgent.match(/windows mobile/i) == "windows mobile";if(bIsIpad || bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM) {deviceType = 'phone';} else{deviceType = 'pc';}returndeviceType;}if(browserRedirect() === 'pc') {importScripts('https://demo.dynamsoft.com/dbr_wasm/js/dbr-6.3.0.1.min.js');}else{importScripts('https://demo.dynamsoft.com/dbr_wasm/js/dbr-6.3.0.1.mobile.min.js');}
Чтобы загрузить WebAssembly в iOS Safari быстрее, используйте https://demo.dynamsoft.com/dbr_wasm/js/dbr-6.3.0.1.mobile.min.js.
Инициализируйте считыватель штрих-кода:
varreader;vardynamsoft = self.dynamsoft || {};dynamsoft.dbrEnv = dynamsoft.dbrEnv || {};dynamsoft.dbrEnv.resourcesPath = 'https://demo.dynamsoft.com/dbr_wasm/js/';dynamsoft.dbrEnv.onAutoLoadWasmSuccess = function() {reader = newdynamsoft.BarcodeReader();postMessage({event: "onload",body: "Successfully loaded wasm."});};dynamsoft.dbrEnv.onAutoLoadWasmError = function(status) {postMessage({event: "onerror",body: "Failed to load wasm."});};//https://www.dynamsoft.com/CustomerPortal/Portal/TrialLicense.aspxdynamsoft.dbrEnv.licenseKey = "t0068MgAAAD2IrA1WJjiVx78RfaZ46qMyCY8DaqpvAD57z5QWkwVQkVwZEf7lE+M2QYbnPx9Fu/aFvCL1mz0Kh2YK0milUng=";
Дождитесь события декодирования штрих-кода:
onmessage = function(e) {e = e.data;switch(e.type) {case"decodeBuffer":{self.reader.decodeBuffer(e.body, e.width, e.height, e.width * 4, dynamsoft.BarcodeReader.EnumImagePixelFormat.IPF_ARGB_8888).then(results => {postMessage({event: 'onresult',body: results});}).catch(ex => {postMessage({event: 'onresult',body: 'No barcode detected'});});break;}default:break;}};
В основном потоке создайте веб-воркер:
if(window.Worker) {myWorker = newWorker('worker.js');myWorker.onmessage = function(e) {let data = e.data;if(data.event) {switch(data.event) {case'onload':{document.getElementById('anim-loading').style.display = 'none';buttonFile.disabled = false;buttonVideo.disabled = false;break;}case'onerror':{document.getElementById('anim-loading').style.display = 'none';break}case'onresult':{let context = clearOverlay();let txts = [];try{let results = data.body;let localization;for(vari = 0; i < results.length; ++i) {if(results[i].LocalizationResult.ExtendedResultArray[0].Confidence >= 30) {txts.push(results[i].BarcodeText);localization = results[i].LocalizationResultif(isVideoMode) {drawResult(context, localization, results[i].BarcodeText);}}}barcode_result.textContent = txts.join(', ');if(isVideoMode) {scanBarcode();}} catch(e) {if(isVideoMode) {scanBarcode();} else{barcode_result.textContent = data.body;}}break;}}}};}
Захватите кадр из видео и отправьте его веб-воркеру:
functionscanBarcode() {let context = ctx,width = videoWidth,height = videoHeight;context.drawImage(videoElement, 0, 0, width, height);varbarcodeCanvas = document.createElement("canvas");barcodeCanvas.width = width;barcodeCanvas.height = height;varbarcodeContext = barcodeCanvas.getContext('2d');barcodeContext.drawImage(videoElement, 0, 0, width, height);// read barcodeif(myWorker) {myWorker.postMessage({type: 'decodeBuffer',body: barcodeContext.getImageData(0, 0, width, height).data,width: width,height: height});}}
Draw возвращал результаты при наложении:
functiondrawResult(context, localization, text) {context.beginPath();context.moveTo(localization.X1, localization.Y1);context.lineTo(localization.X2, localization.Y2);context.lineTo(localization.X3, localization.Y3);context.lineTo(localization.X4, localization.Y4);context.lineTo(localization.X1, localization.Y1);context.stroke();context.font = "18px Verdana";context.fillStyle = '#ff0000';let x = [localization.X1, localization.X2, localization.X3, localization.X4];let y = [localization.Y1, localization.Y2, localization.Y3, localization.Y4];x.sort(function(a, b) {returna - b});y.sort(function(a, b) {returnb - a});let left = x[0];let top = y[0];context.fillText(text, left, top + 50);}
Разверните проект, а затем перейдите на страницу приложения:

Исходный код
https://github.com/dynamsoft-dbr/javascript-barcode/tree/master/examples/webworker
Первоначально опубликовано на www.codepool.biz 3 сентября 2018 г.