簡體   English   中英

異步功能阻止執行

[英]Asynchronous function blocks the execution

據我了解,異步函數允許異步執行代碼,但在我的代碼中似乎不起作用:

async function longAsyncWork() {
    await foo(); // takes about 10 seconds to complete
}

console.log('start');
longAsyncWork();
console.log('end');

在longAsyncWork完成 ,在控制台中寫入了“ end”,但是我認為異步功能的目標是允許執行代碼而不會阻止主執行。

也許是console.log調用的特殊性使我看不到真相? 我可以假設在longAsyncWork函數完成之前執行longAsyncWork調用之后的代碼嗎?

Asnyc函數異步工作,但是javascript是單線程的,這意味着瀏覽器一次只能執行一項任務。 您實際上必須在函數內部進行異步操作才能使其真正起作用,但是您可能在其中進行了一些本質上是同步的阻塞操作。 讓我通過舉例更詳細地解釋一下:

 async function fooThatCanBeAsync(){ var result = await fetch("https://stackoverflow.com"); console.log("after async task 1"); return result; } async function fooThatCannotBeAsync(){ var x = 0; for(i=0; i<10000000; i++){ x += i; } console.log("after async task 2"); } fooThatCanBeAsync(); fooThatCannotBeAsync(); console.log("end..."); 

上面這個愚蠢的例子有兩個異步函數。 但是,其中只有一個可以異步運行! 第一個功能嘗試通過發送http請求來獲取內容,這將需要一些時間。 這意味着,cpu現在是空閑的,直到它開始接收結果為止。 通過使此函數async ,您現在可以在兩次之間使用這段時間來執行其他任務。 這就是並發在javascript中的工作方式。

第二個函數執行for循環,進行一些計算。 這些計算不能是異步的,因為沒有辦法中斷它,沒有時間等待,也沒有I / O操作。 僅僅因為您添加了async關鍵字,您就無法更改只有一個cpu線程正在執行該代碼的事實。

簡單地使函數async並不意味着該函數內部的昂貴處理不會阻塞主線程-而是意味着該函數自動返回Promise,並且await可以在其內部使用(除其他外)。 該函數執行的任何同步工作(包括該函數內部由await調用完成的任何同步工作)仍將阻塞主線程。

 const foo = () => new Promise((resolve) => { for (let i = 0; i < 1e9; i++) { } console.log('foo expensive sync work done'); resolve(); }); async function longAsyncWork() { await foo(); // takes about 10 seconds to complete } console.log('start'); longAsyncWork(); console.log('end, still on main thread'); 

longAsyncWork調用解析為(或內部的任何await )的最終承諾直到主線程完成后才解決,但是仍在阻塞任何await之前的同步處理。

如果要確保昂貴的處理不會阻塞主線程,則可以使用網絡工作者代替:

 const workerFn = () => { self.onmessage = () => { for (let i = 0; i < 1e9; i++) { } self.postMessage('done'); } }; const workerFnStr = `(${workerFn})();`; const blob = new Blob([workerFnStr], { type: 'text/javascript' }); const worker = new Worker(window.URL.createObjectURL(blob)); worker.onmessage = (result) => { console.log('result:', result.data); }; console.log('about to post message'); worker.postMessage('arg'); console.log('main thread continuing here'); 

您也可以撥打Promise.resolve()運行前longAsyncWork ,但不同的是工人的版本,這仍然會阻止父窗口(不過,這將是主線程完成 )的線程。 這通常是不可取的,因為它可以阻止用戶與頁面進行交互-網絡工作者通常是更好的選擇。

 const foo = () => new Promise((resolve) => { for (let i = 0; i < 1e10; i++) { } console.log('foo expensive sync work done'); resolve(); }); async function longAsyncWork() { await foo(); // takes about 10 seconds to complete } console.log('start'); Promise.resolve() .then(longAsyncWork); console.log('end, still on main thread'); 
 <p>Page won't display for a while, or if page is already displayed, scrolling won't work, because main thread is blocked</p> 

您的代碼的有效版本。

 const sleep = ms => new Promise(r => setTimeout(r, ms)) async function longAsyncWork() { // await resolves the sleep promise, so it lock longAsyncWork. await sleep(1000) console.log('async') } console.log('start'); // async longAsyncWork is a promise, so if you doesn't lock it with await, it will run async. longAsyncWork(); console.log('end'); 

按下[執行程式碼片段]即可查看其運作方式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM