JavaScript promise 的同步調用行為分析
在 JavaScript 中,Promise 廣泛用于處理異步操作。本文探討 Promise 在同步調用場景下的行為,特別是當 Promise 沒有調用 resolve 或 reject 時,await 表達式對異步函數的影響。
考慮以下代碼:
async function yyy() { console.log('yyy調用xxx開始'); let res = await xxx(); console.log('yyy調用xxx結束', res); } async function xxx() { return new Promise(function(resolve, reject) { // 沒有調用 resolve 或 reject }); } yyy();
yyy 函數使用 await 等待 xxx 函數返回的 Promise。如果 xxx 函數中沒有調用 resolve 或 reject,Promise 將永遠處于 pending 狀態。await 表達式的行為取決于運行環境:
Node.JS 環境:
立即學習“Java免費學習筆記(深入)”;
在 Node.js 中,由于 xxx 返回的 Promise 處于 pending 狀態且沒有其他異步操作(如定時器、網絡請求),Node.js 的事件循環會認為程序已完成并退出。 事件循環不會無限期等待一個未決定的 Promise。
瀏覽器環境:
在瀏覽器環境中,await 會阻塞 yyy 函數的執行,等待 Promise 完成。然而,由于沒有 resolve 或 reject,這個等待是無限期的。 這不會完全凍結瀏覽器,用戶交互通常不受影響,但 yyy 函數后續的 console.log 語句將不會執行。 如果該代碼在一個獨立的腳本中運行,則瀏覽器可能不會報告錯誤,但腳本的其余部分將不會執行。
修改后的示例 (模擬阻塞):
為了更清晰地展示阻塞行為,我們可以修改代碼:
async function yyy() { console.log('yyy調用xxx開始'); let res = await xxx(); console.log('yyy調用xxx結束', res); } async function xxx() { return new Promise(function(resolve, reject) { let startTime = Date.now(); while (true) { if (Date.now() - startTime > 1000) { console.log('xxx running...'); startTime = Date.now(); } } }); } yyy();
在這個修改后的例子中,xxx 函數包含一個無限循環,模擬一個永遠不會完成的 Promise。 await xxx() 將導致 yyy 函數無限期阻塞,直到手動停止腳本執行。
總結:await 在一個沒有 resolve 或 reject 的 Promise 上會產生不同的結果,取決于運行環境。 在 Node.js 中,程序可能直接退出;在瀏覽器中,await 會無限期阻塞,但通常不會完全凍結瀏覽器。 為了避免這種情況,務必確保所有 Promise 都最終調用 resolve 或 reject。