中文字幕精品亚洲无线码二区,国产黄a三级三级三级看三级,亚洲七七久久桃花影院,丰满少妇被猛烈进入,国产小视频在线观看网站

【每日一面(mian)】async/await 的(de)原理

基礎問答

問:async/await 的(de)原理是什么?

答:關鍵字本身就是 Promise 的語法糖,依托于生成器函數 (Generator) 函數能力實現的。async 關鍵字標志這個函數為異步函數,并且將返回結果封裝為一個 Promise,await 則是暫停當前執行,等待后續的異步操作完成后再恢復,相當于 Generator 的 yield 。只是在 Generator 中,需要手動調用 next() 觸發執行, async 函(han)數(shu)則內置該操作,自動根據 await 的(de)異步(bu)結果執行后續函(han)數(shu)步(bu)驟。

擴展延伸

在上面(mian),提(ti)到了一個生成(cheng)器函數(shu)(shu)(Generator),這個是 JavaScript 中的(de)一種特殊(shu)函數(shu)(shu),可以(yi)暫停(ting)和恢復函數(shu)(shu)執行。在平時的(de)開發中,基本很少(shao)見到這個函數(shu)(shu)的(de)使(shi)用(yong),不過(guo)面(mian)試的(de)時候,只要聊到了 async/await 內容,90% 以(yi)上的(de)概率會問到生成(cheng)器函數(shu)(shu)。

生成器函數使用 function* 語(yu)法(fa)定義,他會(hui)返回一個生成器對象(xiang),而不(bu)是和普通函數一樣返回指定的結(jie)果,如(ru)下示例:

// 定義一個Generator函數,包含2個暫停點(yield)和1個返回值(return)
function* syncGenerator() {
  console.log('1. 函數開始執行');
  yield '第一個暫停結果'; // 第一個暫停點,返回值為'第一個暫停結果'
  console.log('2. 函數恢復執行');
  yield '第二個暫停結果'; // 第二個暫停點,返回值為'第二個暫停結果'
  console.log('3. 函數即將結束');
  return '最終返回結果'; // 函數執行完畢,返回最終結果
}

// 1. 調用Generator函數,返回迭代器(此時函數體未執行)
const genIterator = syncGenerator();
console.log('調用Generator后,函數未執行:', genIterator); // 輸出:Generator {<suspended>}

// 2. 第一次調用next():執行到第一個yield,暫停
const result1 = genIterator.next();
console.log('第一次next()結果:', result1); 
// 輸出順序:
// 1. 函數開始執行
// 第一次next()結果:{ value: '第一個暫停結果', done: false }(done=false表示未執行完畢)

// 3. 第二次調用next():從第一個yield恢復,執行到第二個yield,暫停
const result2 = genIterator.next();
console.log('第二次next()結果:', result2);
// 輸出順序:
// 2. 函數恢復執行
// 第二次next()結果:{ value: '第二個暫停結果', done: false }

// 4. 第三次調用next():從第二個yield恢復,執行到return,結束
const result3 = genIterator.next();
console.log('第三次next()結果:', result3);
// 輸出順序:
// 3. 函數即將結束
// 第三次next()結果:{ value: '最終返回結果', done: true }(done=true表示執行完畢)

// 5. 第四次調用next():函數已結束,后續調用均返回{ value: undefined, done: true }
const result4 = genIterator.next();
console.log('第四次next()結果:', result4); // 輸出:{ value: undefined, done: true }

核心執行規則:

  1. 首次調用 Generator 函數:僅返回迭代器,函數體不執行;
  2. 每次調用 next ():函數從上次暫停位置繼續執行,直到遇到下一個yield或return;
  3. 返回結果結構:next()返回的對象包含value(yield后的值或return的值)和done(布爾值,標識是否執行完畢);
  4. 執行完畢后:后續調用next(),done始終為true,value為undefined。

面試之外,你應該知道,Generator 函數的核心價值在于“異步流程控制”,即,通過yield暫停執行異步操作,等待異步結果返回后, 調用 next() 恢(hui)復執(zhi)行。這(zhe)就是 async/await 的底層(ceng)邏輯雛形。

// 模擬接口請求(異步函數,返回Promise)
function fetchUser() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({ id: 1, name: '前端面試' });
    }, 1000);
  });
}

function fetchOrders(userId) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve([{ orderId: '1001', goods: '面試指南' }]);
    }, 1000);
  });
}

// 定義異步Generator函數:用yield暫停異步操作
function* asyncGenerator() {
  console.log('開始請求用戶信息');
  const user = yield fetchUser(); // 暫停,等待fetchUser的Promise完成
  console.log('用戶信息請求完成:', user);
  
  console.log('開始請求訂單信息');
  const orders = yield fetchOrders(user.id); // 暫停,等待fetchOrders的Promise完成
  console.log('訂單信息請求完成:', orders);
  
  return { user, orders }; // 最終返回結果
}

// 手動執行異步Generator函數(模擬async/await的自動執行器)
function runGenerator(genFn) {
  const genIterator = genFn(); // 獲取迭代器

  // 定義遞歸執行函數
  function handleNext(result) {
    // 若Generator執行完畢,直接返回最終結果
    if (result.done) {
      return Promise.resolve(result.value);
    }

    // 若未執行完畢,處理yield返回的Promise(異步操作)
    // result.value是yield后的值(此處為fetchUser/fetchOrders返回的Promise)
    return Promise.resolve(result.value)
      .then((res) => {
        // 異步操作完成后,調用next(res)恢復執行,將異步結果作為yield的返回值
        return handleNext(genIterator.next(res));
      })
      .catch((err) => {
        // 捕獲異步錯誤,調用throw(err)將錯誤傳入Generator函數
        return handleNext(genIterator.throw(err));
      });
  }

  // 啟動第一次執行
  return handleNext(genIterator.next());
}

// 執行異步Generator函數
runGenerator(asyncGenerator)
  .then((finalResult) => {
    console.log('所有異步操作完成,最終結果:', finalResult);
  })
  .catch((err) => {
    console.log('異步操作出錯:', err);
  });

async/await 本質是(shi)(shi) Generator + 自動執(zhi)行(xing)器的語(yu)法糖,二者核心邏輯可(ke)以一一對應上,只(zhi)是(shi)(shi) async/await 的封裝(zhuang)大大簡化了使用(yong)流程:

特性 Generator 函數 async/await
暫停 / 恢復標識 yield 關鍵字(手動標記暫停點) await關鍵字(自動標記暫停點)
執行控制 需手動調用迭代器的 next() 恢復執行 內置自動執行器,無需手動控制
異步結果處理 需手動用 Promise.resolve 等待異步結果 自動等待 await 后的 Promise 完成
錯誤處理 需手動調用 iterator.throw(err) 傳入錯誤 用 try/catch 自動捕獲錯誤
返回值 調用函數返回迭代器 調用函數返回 Promise
語法簡潔度 較繁瑣,需手動實現執行器 簡潔,無需關注執行細節

面試追問

  1. 生成器函數?是怎么實現 async/await 的?
    具體代碼參考擴展延伸(shen)部分內(nei)容,要代碼描述。

  2. async/await 基礎使用方式,使用 Promise 不(bu)是更(geng)好?為(wei)什(shen)么要用 async/await 關鍵字。

    async function waitRequest() {
        const resp = await axios.request('//hello.com')
        const data = resp.data;
        return data、
    }
    

    可以使用Promise,這個是根據使用場景來的,async/await 只是將異步調用鏈轉換成了同步代碼,閱讀維護起來更方便。
    如(ru)封裝(zhuang)一個等(deng)待延時(shi),通(tong)常(chang)使(shi)用的(de)(de)就是 await + new Promise 來實(shi)現,只是多(duo)數情(qing)況下 Promise 伴隨著的(de)(de)是比較長的(de)(de)調(diao)用鏈,帶(dai)來閱(yue)讀不便,此時(shi)轉換成同(tong)步代碼就清晰(xi)易讀了。

  3. 如果 await 的表達式返回了 reject,需要捕獲嗎?要怎么捕獲?
    需要(yao)捕獲,否則會觸發“Uncaught (in Promise) Error”,中斷代碼(ma)執行,這個類(lei)似于 throw error。需要(yao)使用 try...catch 捕獲 await 表(biao)達式產生(sheng)的錯誤(wu)及reject。

posted @ 2025-10-28 17:25  Achieve前端實驗室  閱讀(256)  評論(0)    收藏  舉報