これはdraw()
、 が WebWorker の戻り値を待たずに を使用するために発生しますrequestAnimationFrame
。継続的にフィルター処理された画像が必要な場合はdraw
、フィルターが適用された後に呼び出す必要があります。
filterWorker.addEventListener('message', function(e) {
ctx.putImageData(e.data, 0, 0);
requestAnimationFrame(draw);
}, false);
ただし、フィルターに時間がかかる場合はdraw
、キャンバスが色付きのデータで塗りつぶされて、変更に気付くのが早い可能性が非常に高くなります (現在のバージョンで FF17 の白黒バージョンを見ることができました)。
コードの何が問題になっていますか?
操作の順序が重要なシナリオで並列計算の機能を使用しています。つまり、各画像が表示される前にフィルターを適用したいとします。MDN を引用させてください:
スレッドセーフについて
Workerインターフェースは、実際の OS レベルのスレッドを生成します。気をつけていないプログラマーは、注意しないと同時実行がコードに「興味深い」影響を与える可能性があることを懸念するかもしれません。
ただし、Web ワーカーは他のスレッドとの通信ポイントを慎重に制御しているため、実際には並行性の問題を引き起こすことは非常に困難です。スレッドセーフでないコンポーネントや DOM にはアクセスできません。また、シリアル化されたオブジェクトを介して特定のデータをスレッドに出し入れする必要があります。したがって、コードで問題を引き起こすには、非常に懸命に取り組む必要があります。
また、実際の OS レベルのスレッドの場合と同様に、なんらかのブロック メカニズムを使用しない限り、実行順序を仮定することはできませんが、これは JavaScript には含まれていません。そのため、同じスレッドで画像を描画して操作する必要があります。
さらなる説明
シーケンシャルケース
次の図を見てください。
これは、techdemo で基本的に行われることです。draw()
ビデオをコピーし、すぐに画像をフィルタリングします。
function draw(v,c,w,h,filter) {
if(v.paused || v.ended) return false;
c.drawImage(v,0,0,w,h);
if (typeof filter === 'undefined') {
// variable is undefined
} else {
var idata = c.getImageData(0,0,w,h);
newdata = filterdata(idata,filter);
c.putImageData(newdata,0,0);
}
setTimeout(draw,20,v,c,w,h,filter);
}
ご覧drawImage
のとおり、次のフィルターの呼び出しの間にギャップはありません。結果の画像は、約 20 ミリ秒間表示されます。フィルターに 1 ミリ秒かかる場合でも、ユーザーはこれに気付かない可能性があります。
パラレルケース
ここで、もう少し複雑になります。黒く塗りつぶされたテキスト ボックスは、キャンバスを直接変更するメソッドです。白いボックスは、トリガーされたイベントまたは登録されたタイムアウトを示し、黒いボックスは、タイムアウトの実行またはイベントの処理を示します。
さて、どうなるでしょうか?draw
約 20 ミリ秒ごとに呼び出され、ビデオをコピーします。次に、ワーカーにメッセージを投稿します。ただし、このメッセージがいつ送信されるかは明記されていません。ワーカーのイベント ループにすぐに配置することも (図に示すように)、「メイン」のイベント ループに配置して後でディスパッチすることもできます (可能性が高い)。
このプロセスは、シーケンシャルな方法と比較して非常に長い時間がかかります。処理されたデータも送り返す必要があること、および と の両方filter
のfilterWorker
イベント リスナが最初に予想したよりも後でトリガーされる可能性があることに注意してください。しかし、実際にデータを処理して表示したとしても、次の への呼び出しにより、draw
すべての苦労が台無しになります。
解決
Web ワーカーを使用しないか、非表示のキャンバスをワーカーのソースとして使用してください。