2017-03-09 12 views
1

WebSocket(paho-mqtt)を使用してブラウザでデータを受信して​​いますが、受信コールバックが別のタスクが終了してスタックされたすべてのデータでは、遅れてデータが失われることはありません。ループが実行されていてもコールバックを起動しないでください。ここで何が起きてるの?。さもなければ、私はこれをどのように達成することができ、ループの中で受信を続けますか?私はクロームコールバックがbig forループ終了後にのみ呼び出されています

setTimeout(() => { 
    console.log('hello!'); 
}, 10); 
for (var i = 0; i < 50000; i++) { 
    console.log('for array'); 
} 

でこれを行う場合、私は

50000 VM15292:5 for array 
VM15292:2 hello! 

が、私は同じような何かを得るべきではありません取得

:私は、次のと同等であると言うしようとしている

この?

1000 VM15292:5 for array 
VM15292:2 hello! 
49000 VM15292:5 for array 

答えて

0

他の人が、うまくブラウザのシングルスレッドの性質を、問題を診断しています。私は可能な解決策を提供します:発電機。ここで

は、問題を示しcodepenです:doWorkは()「する仕事」ボタンをクリックすることで呼び出されたとき http://codepen.io/anon/pen/zZwXem?editors=1111

window.CP.PenTimer.MAX_TIME_IN_LOOP_WO_EXIT = 60000; 

function log(message) { 
    const output = document.getElementById('output'); 
    output.value = output.value + '\n' + message; 
} 

function asyncTask() { 
    log('Simulated websocket message') 
} 


function doWork() { 
    const timer = setInterval(1000, asyncTask); 
    let total = 0; 
    for (let i = 1; i < 100000000; i++) { 
    const foo = Math.log(i) * Math.sin(i); 
    total += foo; 
    } 
    log('The total is: '+ total); 
    clearInterval(timer); 
} 

、asyncTaskが実行されることはありませんし、UIはロックアップ。恐ろしいUX。

次の例では、長期実行タスクを実行するためにジェネレータを使用しています。

http://codepen.io/anon/pen/jBmoPZ?editors=1111

//Basically disable codepen infinite loop detection, which is faulty for generators 
window.CP.PenTimer.MAX_TIME_IN_LOOP_WO_EXIT = 120000; 

let workTimer; 

function log(message) { 
    const output = document.getElementById('output'); 
    output.value = output.value + '\n' + message; 
} 

function asyncTask() { 
    log('Simulated websocket message') 
} 

let workGenerator = null; 
function runWork() { 
    if (workGenerator === null) { 
    workGenerator = doWork(); 
    } 
    const work = workGenerator.next(); 
    if (work.done) { 
     log('The total is: '+ work.value); 
     workerGenerator = null; 
    } else { 
    workTimer = setTimeout(runWork,0); 
    } 
} 

function* doWork() { 
    const timer = setInterval(asyncTask,1000); 
    let total = 0; 
    for (let i = 1; i < 100000000; i++) { 
    if (i % 100000 === 0) { 
     yield; 
    } 
    if (i % 1000000 == 0) { 
     log((i/100000000 * 100).toFixed(1) + '% complete'); 
    } 
    const foo = Math.log(i) * Math.sin(i); 
    total += foo; 
    } 
    clearInterval(timer); 
    return total; 
} 

ここでは、発電機での作業、およびUIの「ドゥ仕事」ボタンから呼び出すための発電機のランナーを作成します。これはChromeの最新バージョンで実行されますが、私は他のブラウザでは話すことができません。典型的には、プロダクションビルド用のES5構文にジェネレータをコンパイルするには、babelのようなものを使用します。

ジェネレータは、10000行の計算ごとに生成され、100000行ごとにステータス更新を発行します。ジェネレータランナー 'runWork'はジェネレータのインスタンスを作成し、next()を繰り返し呼び出します。ジェネレータは、次のyieldまたはreturn文に当たるまで実行されます。ジェネレータが生成した後、ジェネレータランナは、setTimeoutを0ミリ秒で呼び出し、ハンドラ関数として自身を使用することによってUIスレッドを放棄します。これは、通常、アニメーションフレームごとに(理想的には)呼び出されることを意味します。これはジェネレータが完了フラグを返すまで行われ、ジェネレータランナは戻り値を取得してクリーンアップすることができます。

ここでは、codepenを再作成する必要がある場合は例えばHTML:

<input type='button' value='Do Work' onclick=doWork() /> 
<textarea id='output' style='width:200px;height:200px'></textarea> 
0

Javascriptエンジンはシングルスレッド化する傾向があります。だから、

あなたは(いくつかのIOを行うことなど)を得ていない長時間実行タイトなループである場合、あなたがJavaScriptコードを実行すると、コールバックは、ループが

3

を終了するまで実行する機会を得ることはありません(Web Workersまたは他の特殊な技術を使用しない限り)ブラウザは、単一のスレッドで実行されます。それはあまり重要ではないかもしれませんが、そうです。

あなたのコードはforループ(同期)とsetTimeout(非同期)への呼び出しで構成されています。一度に実行できるJavaScriptは1つだけなので、forループはsetTimeoutによって中断されることはありません。ブラウザは常に終了する現在実行中のコードを待つため

実際には、あなたは、forループ完了するまでに10以上のミリ秒を要し、非常に集中的な操作が含まれている場合、あなたのsetTimeoutコールバックは、実際に、はそのマーク過去遅れるかもしれませんイベントループを継続して実行してください。

setTimeout(() => { 
 
    console.log('hello!'); 
 
}, 10); 
 
for (var i = 0; i < /* 50000 */ 5; i++) { 
 
    console.log('for array'); 
 
}

関連する問題