ワーカー(Webワーカー)からの関数呼び出しの最適化

著名なKhabrosocommunityを歓迎し、この集団情報銀行への貢献として

-労働者との仕事の経験を共有したい。



ワーカー(Webワーカー)。分離されたコードのセクションを別のスレッドで実行できるテクノロジー。 ワーカーからのコードはGUIの速度を落とすことはなく、ページ上のコードよりも高速に実行されるため、グラフィックスや暗号化の描画などの厳しい計算にワーカーを使用することは非常に魅力的です。



まだこの技術に出会っていない人- ここでは、その基本を知ることができます。



以下に、複数の関数を呼び出す必要がある場合にワーカーから関数を呼び出すために必要なコードの量を減らすことができる小さなライフハックについて説明します。



通常、ワーカーに関数が1つしかない場合、次のように記述します。



外部(ページコード内):



var worker = new Worker("myscript.js"); worker.onmessage (event.data){workerallback(event.data);} function workerallback(data){ /*do something with data object;*/} worker.postMessage({some:"some"});
      
      







内部(ワーカーコード内):



 onmessage = function (event) {postMessage(mySingleFunction(event.data));}
      
      







これまでのところ、すべてがシンプルでエレガントです。



ただし、外部から呼び出されるワーカーに別の関数を追加すると、これらの関数の呼び出しを提供するコードの量が増え、それほどエレガントに見えなくなります。



外:



 function firstFunctionallback(data){ /*do something with data object;*/} function secondFunctionallback(data){ } worker.onmessage (msg){ if(msg.data.callback == "firstFunctionallback"){ firstFunctionallback(msg.data.result); } if(msg.data.callback == "secondFunctionallback"){ firstFunctionallback(msg.data.result); } } worker.postMessage({functionName: "firstFunction", data: data);
      
      







中:



 onmessage = function (event) { var functionName = event.data.functionName; if(functionName == "firstFinction"){ postMessage({callback: "firstFunctionallback", result: firstFinction(event.data.data)}); } if(functionName == "secondFunction"){ postMessage({callback: "secondFunctionallback", result: secondFunction(event.data.data)}); } ... }
      
      







このアプローチでは、匿名関数をコールバックとして使用することはできません。新しい関数をワーカーに追加するたびに、ワーカーの外部および内部でこの関数を呼び出すための一定量の追加コードを記述する必要があります。



これを避けるために、この作業を実行するオブジェクトでワーカーをラップできます。



このようなオブジェクトをそれぞれPerformerと呼び、外部コードに配置します。



 function Performer(scriptSource) { var worker = new Worker(scriptSource), callbacks = {}, nextRequestId = 0; this.perform = function(functionName, params, callback) { callbacks["request_" + (++nextRequestId)] = callback; worker.postMessage( {functionName: functionName, params: params, requestId: nextRequestId} ); } worker.onmessage = function(msg) { callbacks["request_" + msg.data.requestId](msg.data.result); delete callbacks["request_" + msg.data.requestId]; } }
      
      







ワーカーの内部コードで、外部メッセージハンドラーを変更します。



 onmessage = function (event) { var requestId = event.data.requestId; var workerFunction = eval(event.data.functionName); var params = event.data.params; var result = workerFunction(params); postMessage({result: result, requestId: requestId}); }
      
      







これで、補助コードを記述することなく、任意の関数をワーカーに追加し、外部からそれらを呼び出すことができ、コールバックで匿名関数を使用することもできます。



 var performer = new Performer("myscript.js"); performer.perform("firstFunction", {some: "some"}, function(result){console.log("result1="+result);}); performer.perform("secondFunction", {some: "some"}, function(result){console.log("result2="+result);});
      
      







ワーカーが別のスクリプトファイルに配置されておらず、ページに埋め込まれている場合、

次に、パフォーマコードでブラウザ間の違いを考慮する必要があります。



これらを考慮すると、ワーカーの初期化を担当するパフォーマーの部分は次のようになります。



 function Performer(scriptText) { var worker = null; try {// Firefox var Url = window.webkitURL || window.URL; worker = new Worker(Url.createObjectURL(new Blob([ scriptText ]))); } catch (browserNotSupportWindowUrl) { try {// Chrome worker = new Worker('data:application/javascript,' + encodeURIComponent(scriptText)); } catch (browserNotSupportWorkers) {// Opera eval(scriptText); worker = { postMessage : function(data) { var workerFunction = eval(data.functionName); worker.onmessage({ data : { result : workerFunction(data.params), requestId : data.requestId } }); } }; } } ... }
      
      







および作成は、それぞれ次のとおりです。



 var performer = new Performer($('#myscript').text());
      
      







したがって、ワーカーをサポートしないブラウザでも、ワーカーコードは実行速度が遅くなります。



UPD:Unknown Benefactorに招待してくれてありがとう)。



All Articles