成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

解決async/await頁面卡頓:理解并發處理的正確方法

開發 前端
掌握這些并發處理技巧,你就能充分利用async/await的優勢,寫出既高效又不會讓用戶感覺頁面卡頓的JavaScript代碼了。

你可能遇到過這種情況:你在JavaScript中使用了async/await來處理異步操作,比如循環請求用戶列表數據,結果頁面卻長時間白屏,直到所有請求都完成后才顯示內容。這讓你感到困惑:不是說async/await是非阻塞的嗎?它怎么會讓頁面卡住呢?

這個問題觸及了async/await、瀏覽器任務處理和頁面渲染的核心機制。讓我們一步步搞清楚。

誤解澄清:await 到底會不會阻塞?

先說最重要的:async/await本身不會阻塞瀏覽器的JavaScript主線程。 它只是讓寫異步代碼看起來像寫同步代碼的一種方式。

當JavaScript引擎碰到await關鍵字時,它會暫停當前async函數的執行,把控制權交還給瀏覽器的主線程。

這時主線程是空閑的,它可以去做其他事情:響應用戶的點擊、滾動,運行其他腳本代碼,還有最重要的——更新頁面顯示(渲染)。

等到await后面的那個操作(通常是一個Promise)完成后,瀏覽器會在合適的時候(主線程空閑時)把這個async函數暫停的地方繼續執行下去。

聽起來很完美?那為什么頁面還是卡住了呢?

真正的罪魁禍首:一個接一個的等待

問題往往出在代碼怎么寫上。看看下面這個常見的錯誤例子:

// 模擬一個獲取用戶數據的api請求
functionfetchUser(id) {
returnnewPromise(resolve => {
setTimeout(() => {
console.log(`獲取到用戶 ${id}`); // 模擬網絡請求
      resolve({ id: id, name: `用戶 ${id}` });
    }, 1000); // 假設每個請求需要1秒鐘
  });
}

// 錯誤做法:在循環里一個接一個地等
asyncfunctiongetAllUsers(userIds) {
console.time('獲取所有用戶耗時');
const users = [];
for (const id of userIds) {
// 關鍵問題:這里會停下來等,等上一個請求徹底完成,才會開始下一個
const user = await fetchUser(id);
    users.push(user);
  }
console.timeEnd('獲取所有用戶耗時');
// 假設這里是把用戶數據顯示到頁面上
  showUsers(users);
return users;
}

const userIds = [1, 2, 3, 4, 5];
getAllUsers(userIds);
// 控制臺輸出:獲取所有用戶耗時: 約5000毫秒

問題很明顯:這5個請求是一個接一個執行的。

第一個請求發出后,代碼就停下來等它1秒完成,然后才開始第二個請求,再等1秒,如此反復。

總共花了差不多5秒鐘。而更新頁面顯示的那個showUsers(users)函數,必須等到這漫長的5秒全部結束后才會被調用。

在這5秒里,雖然瀏覽器的主線程在每次await等待時確實可以去處理別的事情(比如你點了按鈕它可能還能響應)。

但因為你的代碼邏輯就是讓所有事情排隊做,頁面在等待期間沒有任何新內容可以顯示。

用戶看到的就是一個長時間空白或內容不更新的頁面,感覺就像頁面“卡死”了。

解決之道:讓請求一起 - Promise.all

如果這些請求之間不需要等對方的結果(比如獲取用戶1的數據不需要先知道用戶2的數據),那完全可以讓它們同時發出去!這就是Promise.all的用武之地。

Promise.all接收一個包含多個Promise(代表那些異步操作)的數組。它自己返回一個新的Promise。

這個新Promise會等到數組里所有的Promise都成功完成(resolved)后,才成功,并把所有結果打包成一個數組給你。

改造上面的代碼:

asyncfunctiongetAllUsersFast(userIds) {
console.time('并行獲取所有用戶耗時');
// 1. 創建請求數組:每個元素都是 fetchUser(id) 調用返回的Promise
const userPromises = userIds.map(id => fetchUser(id));

// 2. 使用 Promise.all 等待所有請求完成
const users = awaitPromise.all(userPromises);

console.timeEnd('并行獲取所有用戶耗時'); // 輸出:約1000毫秒
  showUsers(users);
return users;
}

getAllUsersFast(userIds);

效果立竿見影!總時間從5秒縮短到了大約1秒(取決于最慢的那個請求)。頁面也能更快地顯示出用戶數據,用戶體驗好得多。

更多實用工具:不同場景用不同方法

Promise.all很強大,但并不是唯一的選擇。根據你的具體需要,還有其他好幫手:

1.Promise.allSettled:每個都要結果,不管成功失敗如果有些請求可能會失敗,但你不想讓一個失敗就中斷所有,還想知道每個請求最終是成功還是失敗了,用Promise.allSettled。

asyncfunctiongetUsersWithStatus(userIds) {
const promises = userIds.map(id => fetchUser(id).catch(error => error)); // 捕獲錯誤,避免整個Promise.allSettled失敗
const results = awaitPromise.allSettled(promises);

// 處理結果:results 是一個數組,每個元素是對象
// { status: 'fulfilled', value: 結果 } 或 { status: 'rejected', reason: 錯誤原因 }
  results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('成功:', result.value);
    } else {
console.log('失敗:', result.reason);
    }
  });
return results; // 或者根據 status 過濾出成功的數據
}

2.Promise.race 和 Promise.any:誰快用誰
1)Promise.race: 只要數組里有一個Promise完成(無論是成功還是失敗),它就立刻完成,結果或錯誤就是那個最快的Promise的。
適合做超時控制或者從多個來源取最快響應(比如測哪個CDN快)。

asyncfunctiongetFirstResponse() {
const timeoutPromise = newPromise((_, reject) =>setTimeout(() => reject(newError('超時!')), 500));
const dataPromise = fetchUser(1);

try {
const result = awaitPromise.race([dataPromise, timeoutPromise]);
console.log('成功獲取數據:', result);
  } catch (error) {
console.log('出錯或超時:', error.message);
  }
}

2)Promise.any: 等待第一個成功完成的Promise。只有數組里所有的Promise都失敗了,它才失敗。適合需要嘗試多個途徑,只要有一個成功就行。

asyncfunctiongetFromAnySource(sources) {
try {
const firstSuccess = awaitPromise.any(sources.map(source => fetch(source)));
console.log('從最快成功的源獲取:', firstSuccess);
  } catch (errors) { // 注意:錯誤是 AggregateError
console.log('所有源都失敗了:', errors);
  }
}

3)控制同時請求的數量:別把服務器壓垮如果你的用戶ID列表有1000個,用Promise.all會瞬間發出1000個請求。

這可能會讓你的服務器崩潰,或者被瀏覽器限制(瀏覽器通常對同一域名有并發請求數限制,比如6-8個)。

這時候你需要一個“池子”來控制同時進行的請求數量。這里提供一個簡單但有效的實現方法:

asyncfunctionrunWithConcurrency(tasks, maxConcurrent) {
const results = []; // 存放所有任務的最終結果(Promise)
const activeTasks = []; // 當前正在執行的任務對應的Promise(用于跟蹤)

for (const task of tasks) {
// 1. 創建代表當前任務的Promise。`() => task()` 確保任務在需要時才啟動
const taskPromise = Promise.resolve().then(task);
    results.push(taskPromise); // 保存結果,最后統一用 Promise.all 等

// 2. 創建任務完成后的清理操作:從 activeTasks 中移除自己
const removeFromActive = () => activeTasks.splice(activeTasks.indexOf(removeFromActive), 1);
    activeTasks.push(removeFromActive); // 注意:這里存的是清理函數對應的Promise

// 3. 如果當前活躍任務數已達上限,就等任意一個完成
if (activeTasks.length >= maxConcurrent) {
awaitPromise.race(activeTasks); // 等 activeTasks 數組里任意一個Promise完成
    }

// 4. 將清理操作與實際任務完成掛鉤
    taskPromise.then(removeFromActive, removeFromActive); // 無論成功失敗都清理
  }

// 5. 等待所有任務完成(無論是否在活躍池中)
returnPromise.allSettled(results); // 或者用 Promise.all(results) 只關心成功
}

// 使用示例
const userIds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 將 fetchUser(id) 調用包裝成無參數的函數數組
const tasks = userIds.map(id =>() => fetchUser(id));

// 最多同時發出 3 個請求
runWithConcurrency(tasks, 3).then(results => {
console.log('所有用戶獲取完成 (并發控制):', results);
});

這個函數會確保最多只有maxConcurrent個請求同時在進行。

當一個請求完成,池子里有空位了,才會開始下一個請求。在實際項目中,你也可以使用成熟的庫如 p-limit 或 async 的 queue 方法來實現更強大的并發控制。

關鍵總結

  • async/await 本身不會阻塞瀏覽器主線程
  • 頁面卡頓通常是因為代碼邏輯(如在循環中串行await)導致了不必要的長時間等待
  • 對于獨立的異步任務(如多個API請求),使用 Promise.all 讓它們并行執行是大幅提升速度和用戶體驗的關鍵。
  • 根據需求選擇工具:Promise.allSettled(都要結果)、Promise.race/Promise.any(用最快的)、手動或庫實現的并發控制(防服務器過載)。
  • 理解瀏覽器的事件循環和渲染機制有助于寫出更流暢的代碼。記住:長時間的同步邏輯(包括在async函數里連續await造成的等待)會推遲渲染。

掌握這些并發處理技巧,你就能充分利用async/await的優勢,寫出既高效又不會讓用戶感覺頁面卡頓的JavaScript代碼了。

責任編輯:龐桂玉 來源: web前端開發
相關推薦

2025-07-21 10:00:00

JavaScript線程開發

2016-11-22 11:08:34

asyncjavascript

2023-05-08 11:49:05

asyncawait場景

2024-09-02 14:12:56

2017-08-02 14:17:08

前端asyncawait

2014-07-15 10:31:07

asyncawait

2012-05-30 15:40:16

大并發并發解決方案

2023-10-08 10:21:11

JavaScriptAsync

2024-06-25 08:33:48

2024-03-05 18:15:28

AsyncAwait前端

2021-06-28 08:10:59

JavaScript異步編程

2016-10-27 17:05:32

Chrome瀏覽器

2024-01-29 00:35:00

Go并發開發

2024-02-02 15:21:08

工具頁面性能

2024-06-03 08:22:33

微信小程序頁面切換刪除定位法

2012-07-22 15:59:42

Silverlight

2021-07-20 10:26:12

JavaScriptasyncawait

2022-08-27 13:49:36

ES7promiseresolve

2017-04-10 15:57:10

AsyncAwaitPromise

2023-07-28 07:31:52

JavaScriptasyncawait
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产一区在线视频 | 乳大翘臀1v1h糙汉 | 亚洲欧美综合另类 | 日韩中文字幕在线观看 | 韩日精品视频 | 免费网站观看www在线观看 | 日本中文字幕在线观看 | 色爽视频| 天堂资源网 | 韩日在线视频 | 日韩免费视频 | 欧美日韩在线观看视频 | 水蜜桃一区二区 | 日韩免费一区 | 狠狠干2018 | 亚洲国产精品久久久久 | 成年人国产| 天堂网在线播放 | 国产香蕉在线观看 | 天天插天天射 | 四虎4hu永久免费网站影院 | 精东影业一区二区三区 | 日本在线一区二区三区 | 欧美日韩精品 | 动漫av在线 | 视频在线观看一区 | 久久精品福利 | 欧美精品在线视频 | 中文字幕在线不卡 | 91亚洲国产成人精品性色 | 欧美手机在线 | 国产精品一区一区三区 | 日本中文字幕在线观看 | 亚洲第一第二区 | 不卡av网站 | 激情五月综合网 | www.久 | 天海翼在线视频 | 天天射综合 | 一区二区三区精品视频 | 九九热在线播放 |