欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript異步編程 Async/Await 使用從原理到最佳實(shí)踐記錄

 更新時(shí)間:2025年05月26日 14:44:31   作者:Micro麥可樂  
Async/Await 的引入徹底改變了 JavaScript 異步編程的面貌,通過本文的講解,相信小伙伴們可以掌握 Async/Await 的使用精髓,將使您的 JavaScript 代碼在保持高性能的同時(shí),獲得質(zhì)的可讀性和可維護(hù)性提升,感興趣的朋友一起看看吧

1.背景與概念

在傳統(tǒng) JavaScript 開發(fā)中,開發(fā)者長(zhǎng)期面臨回調(diào)地獄的困擾。隨著 ES6 Promise 的出現(xiàn),異步代碼的可讀性得到改善,但鏈?zhǔn)秸{(diào)用依然存在嵌套問題。2017 年 ES8 正式引入的 Async/Await 語法,讓異步代碼第一次擁有了同步代碼般的可讀性。

async 函數(shù)是基于 Promise 的語法糖,用于簡(jiǎn)化異步操作的書寫方式。使用 async 聲明的函數(shù)會(huì)隱式返回一個(gè) Promise,函數(shù)體內(nèi)部可以通過 await 暫停執(zhí)行,直到對(duì)應(yīng)的 Promise 完成或拋出錯(cuò)誤后再繼續(xù)執(zhí)行。
await 操作符只能在 async 函數(shù)或模塊頂層中使用,用于等待一個(gè) Promise 解決,并將其結(jié)果作為表達(dá)式的值返回;如果 Promise 被拒絕,則會(huì)在該位置拋出異常,可配合常規(guī)的 try...catch 進(jìn)行捕獲處理。

這種寫法極大地提升了異步代碼的可讀性,使得我們可以像編寫同步代碼一樣直觀地處理異步邏輯,同時(shí)保留了后臺(tái)并發(fā)執(zhí)行的優(yōu)勢(shì)。

2. 語法詳解

2.1 聲明與返回值

async function foo() {
  return 42;
}

上例中, foo() 會(huì)返回一個(gè)已解決(fulfilled)的 Promise,其值為 42;等價(jià)于:

function foo() {
  return Promise.resolve(42);
}

這是因?yàn)槿魏?async 函數(shù)內(nèi)的返回值都會(huì)被自動(dòng)封裝為 Promise

2.2 使用 await 暫停執(zhí)行

async function fetchData() {
  let response = await fetch('/api/data');
  let data = await response.json();
  return data;
}

代碼解釋:

  • 第一行的 await fetch(...) 會(huì)暫停 fetchData 的執(zhí)行,直到 fetch 返回的 Promise 完成,并將其結(jié)果賦值給 response
  • 第二行的 await response.json() 同理,等待解析 JSON 后再繼續(xù)執(zhí)行
  • 如果任一 Promise 拒絕,則會(huì)在該 await 位置拋出異常,可在外層使用 try...catch 捕捉。

2.3 錯(cuò)誤處理

async function safeFetch() {
  try {
    let res = await fetch('/bad/url');
    let json = await res.json();
    return json;
  } catch (err) {
    console.error('請(qǐng)求失?。?, err);
    throw err; // 可再次拋出或返回默認(rèn)值
  }
}

上述模式與同步代碼中使用 try…catch 完全一致,大大簡(jiǎn)化了基于 Promise 鏈?zhǔn)?.catch() 的寫法

2.4 語法規(guī)則

下面我們看看我們常用的一些使用語法

// 聲明異步函數(shù)
async function fetchUser() {
  return { name: 'Alice', age: 28 }; // 自動(dòng)包裝為Promise
}
// 使用箭頭函數(shù)
const fetchData = async () => {
  const res = await fetch('/api/data');
  return res.json();
};
// 立即調(diào)用模式
(async () => {
  const data = await fetchData();
  console.log(data);
})();

3. 并發(fā)與性能

3.1 順序等待 vs 并行等待

默認(rèn)情況下,連續(xù)的 await 會(huì)串行執(zhí)行:

let a = await task1();
let b = await task2();

若兩者互不依賴,可改為并行:

let [a, b] = await Promise.all([task1(), task2()]);

3.2 并行執(zhí)行優(yōu)化

通過上面 順序等待 vs 并行等待 的介紹,通常我們可以按照以下形式來進(jìn)行優(yōu)化(模擬請(qǐng)求)

// 順序執(zhí)行(總耗時(shí) = 各請(qǐng)求耗時(shí)之和)
async function serialRequests() {
  const res1 = await fetch('/api/1');
  const res2 = await fetch('/api/2');
  return [await res1.json(), await res2.json()];
}
// 并行執(zhí)行(總耗時(shí) ≈ 最慢請(qǐng)求耗時(shí))
async function parallelRequests() {
  const [res1, res2] = await Promise.all([
    fetch('/api/1'),
    fetch('/api/2')
  ]);
  return await Promise.all([res1.json(), res2.json()]);
}

3.2 限制并發(fā)數(shù)量

在需要對(duì)大量異步任務(wù)進(jìn)行限流時(shí),可使用第三方庫(如 p-limit)或自己實(shí)現(xiàn)簡(jiǎn)單隊(duì)列,避免一次性發(fā)起過多請(qǐng)求導(dǎo)致資源競(jìng)爭(zhēng)或網(wǎng)絡(luò)擁堵

4. 異步迭代

ES2018 引入了 for await...of,用于遍歷異步可迭代對(duì)象(如異步生成器):

async function* gen() {
  yield await fetchChunk(1);
  yield await fetchChunk(2);
}
(async () => {
  for await (let chunk of gen()) {
    console.log(chunk);
  }
})();

該語法在處理流式數(shù)據(jù)(例如文件分塊下載)時(shí)非常有用

5 常見問題解決方案

5.1 請(qǐng)求重試機(jī)制

在外面日常開發(fā)中,會(huì)遇到請(qǐng)求失敗需要重試的需求,來看看以下模擬代碼

async function fetchWithRetry(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const res = await fetch(url);
      return await res.json();
    } catch (err) {
      if (i === retries - 1) throw err;
      await new Promise(r => setTimeout(r, 1000 * (i + 1)));
    }
  }
}

5.2 競(jìng)態(tài)條件處理

當(dāng)多個(gè)請(qǐng)求并發(fā)執(zhí)行時(shí),可能因網(wǎng)絡(luò)延遲、服務(wù)器響應(yīng)速度差異等問題導(dǎo)致響應(yīng)順序與發(fā)送順序不一致問題。
更詳細(xì)講解可以查閱博主寫過一篇【 前端請(qǐng)求亂序問題分析與AbortController、async/await、Promise.all等解決方案】

以下僅展現(xiàn)實(shí)現(xiàn)代碼:

let lastController = null;
async function search(query) {
  // 取消前一個(gè)未完成的請(qǐng)求
  if (lastController) lastController.abort();
  const controller = new AbortController();
  lastController = controller;
  try {
    const res = await fetch(`/api/search?q=${query}`, {
      signal: controller.signal
    });
    return await res.json();
  } catch (err) {
    if (err.name !== 'AbortError') throw err;
  }
}

5.3 異步生成器

在 ·async function*· 中,你既可以使用 ·await·,也可以使用 ·yield·,將異步任務(wù)與懶加載結(jié)合

async function* asyncGenerator() {
  for (let i = 0; i < 3; i++) {
    await delay(1000);
    yield i;
  }
}

這種方式適合按需獲取異步數(shù)據(jù),提高資源利用率

5.4 處理非 Promise 值

await 后可以跟任意表達(dá)式,如果其值不是 Promise,則會(huì)被包裝為立即解決的 Promise。例如:

let x = await 123; // 相當(dāng)于 await Promise.resolve(123)

但建議對(duì)非異步操作避免使用 await,以免誤導(dǎo)

5.5 常見陷阱

  • 遺忘 await:調(diào)用 async 函數(shù)但未加 await,會(huì)得到未決(pending)的 Promise 而非預(yù)期結(jié)果
  • 在非 async 環(huán)境使用 await:僅在模塊頂層或 async 函數(shù)內(nèi)部可用,否則會(huì)拋語法錯(cuò)誤
  • Promise.all 中單個(gè)失敗導(dǎo)致整體失敗:若需要容忍部分失敗,可對(duì)內(nèi)部 Promise 使用 .catch() 處理,避免整體拒絕
  • 濫用并發(fā):同時(shí)發(fā)起過多網(wǎng)絡(luò)請(qǐng)求可能觸發(fā)限流或阻塞,建議根據(jù)場(chǎng)景調(diào)整并發(fā)策略

6. 性能優(yōu)化實(shí)踐

博主這里例舉兩個(gè)優(yōu)化的案例:內(nèi)存管理以及優(yōu)先加載優(yōu)化

6.1 內(nèi)存管理

常見一些大量數(shù)據(jù)的獲取下載

async function processLargeData() {
  const data = await getHugeData(); // 大數(shù)據(jù)量
  // 分塊處理
  for (let i = 0; i < data.length; i += 1000) {
    const chunk = data.slice(i, i + 1000);
    await processChunk(chunk);
    data[i] = null; // 及時(shí)釋放內(nèi)存
  }
}

6.2 優(yōu)先加載優(yōu)化

async function loadCriticalResources() {
  // 預(yù)加載非關(guān)鍵資源
  const nonCritical = fetch('/non-critical').then(r => r.json());
  // 優(yōu)先處理關(guān)鍵資源
  const user = await fetchUser();
  const config = await fetchConfig();
  // 等待非關(guān)鍵資源
  const data = await nonCritical;
  return { user, config, data };
}

7. 結(jié)語

Async/Await 的引入徹底改變了 JavaScript 異步編程的面貌。通過本文的講解,相信小伙伴們可以掌握 Async/Await 的使用精髓,將使您的 JavaScript 代碼在保持高性能的同時(shí),獲得質(zhì)的可讀性和可維護(hù)性提升。

到此這篇關(guān)于JavaScript異步編程 Async/Await 使用詳解:從原理到最佳實(shí)踐的文章就介紹到這了,更多相關(guān)js異步編程Async/Await 使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • wavesurfer.js繪制音頻波形圖的實(shí)現(xiàn)

    wavesurfer.js繪制音頻波形圖的實(shí)現(xiàn)

    這篇文章主要介紹了wavesurfer.js繪制音頻波形圖的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • TypeScript利用TS封裝Axios實(shí)戰(zhàn)

    TypeScript利用TS封裝Axios實(shí)戰(zhàn)

    這篇文章主要介紹了TypeScript利用TS封裝Axios實(shí)戰(zhàn),TypeScript封裝一遍Axios,能進(jìn)一步鞏固TypeScript的基礎(chǔ)知識(shí),需要的小伙伴可以參考一下
    2022-06-06
  • JavaScript限定復(fù)選框的選擇個(gè)數(shù)示例代碼

    JavaScript限定復(fù)選框的選擇個(gè)數(shù)示例代碼

    有10個(gè)復(fù)選框,用戶最多只能勾選3個(gè),否則就灰掉所有復(fù)選框,具體實(shí)現(xiàn)思路及代碼如下,感興趣的朋友可以參考下,希望對(duì)大家有所幫助
    2013-08-08
  • javascript iframe中打開文件,并檢測(cè)iframe存在否

    javascript iframe中打開文件,并檢測(cè)iframe存在否

    從iframe中打開文件,并檢測(cè)iframe存在否如果說只是檢測(cè)頁面存在否,直接設(shè)置target用偽協(xié)議就可以解決了...
    2008-12-12
  • Js中pick函數(shù)的具體使用

    Js中pick函數(shù)的具體使用

    本文主要介紹了Js中pick函數(shù)的具體使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-09-09
  • js拖拽功能實(shí)現(xiàn)代碼解析

    js拖拽功能實(shí)現(xiàn)代碼解析

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)拖拽功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • 原生js實(shí)現(xiàn)簡(jiǎn)易計(jì)算器

    原生js實(shí)現(xiàn)簡(jiǎn)易計(jì)算器

    這篇文章主要為大家詳細(xì)介紹了原生js實(shí)現(xiàn)簡(jiǎn)易計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 使用js修改客戶端注冊(cè)表的方法

    使用js修改客戶端注冊(cè)表的方法

    這篇文章介紹了使用js修改客戶端注冊(cè)表的方法,有需要的朋友可以參考一下
    2013-08-08
  • JS/jQuery實(shí)現(xiàn)超簡(jiǎn)單的Table表格添加,刪除行功能示例

    JS/jQuery實(shí)現(xiàn)超簡(jiǎn)單的Table表格添加,刪除行功能示例

    這篇文章主要介紹了JS/jQuery實(shí)現(xiàn)超簡(jiǎn)單的Table表格添加,刪除行功能,結(jié)合實(shí)例形式詳細(xì)分析了JS與jQuery針對(duì)Table表格添加,刪除行功能的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2019-07-07
  • JavaScript實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器

    JavaScript實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-01-01

最新評(píng)論