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

【每日一面】對(dui) Promise.race 的理解

基礎問答

問:有使用過 Promise.race 嗎(ma),說說他的作用。

答:Promise.race 接收一個 Promise 數組(或者一個具有迭代器的對象)作為參數,返回一個新的Promise,這個新的 Promise 結果是數組中第一個狀態變更的Promise對象,無所謂這個狀(zhuang)態是否是成功(fulfilled)還是失敗(bai)(rejected)。后續Promise數組中(zhong)的其他Promise對(dui)象狀(zhuang)態變更都不再關注(zhu)。

擴展延伸

Promise 基礎

Promise 是 ES6 引入的異步編程解決方案,用于表示一個異步操作的最終完成(或失敗)及其結果值。它的核心價值是:

  • 解決 “回調地獄”:將嵌套的回調邏輯轉為鏈式調用(then鏈),代碼更清晰;
  • 統一異步操作接口:無論異步操作是 “成功” 還是 “失敗”,都通過統一的 Promise 對象處理,避免回調函數分拆(如成功回調、失敗回調分離)。

Promise 有且僅有三種狀態,且狀態變化是單向不可逆的,這三種狀態(tai)分別是:

  • pending(等待態):初始狀態,異步操作未完成;
  • fulfilled(成功態):異步操作完成,Promise 狀態從pending轉為fulfilled,并攜帶成功結果(value);
  • rejected(失敗態):異步操作失敗,Promise 狀態從pending轉為rejected,并攜帶失敗原因(reason)。

這是 Promise 的(de)核(he)心特性,也是所有方法(fa)設(she)計的(de)基礎。

狀態變化規則

  1. 只能從pending轉為fulfilled,或從pending轉為rejected;
  2. 一旦狀態轉為fulfilled或rejected,就會 “凝固”,后續無法再改變狀態;
  3. 狀態變化時,會觸發對應的回調函數(then的成功回調、catch的失敗回調)。

Promise 的核心實例方法:

  1. then 方法:處理成功 / 失敗結果
  2. catch 方法:專門處理失敗結果,catch(onRejected) 等價于then(null, onRejected),是處理rejected狀態的語法糖;
  3. finally 方法:無論成功失敗都執行

Promise靜態方法

除了Promise.race,Promise 還有Promise.all/Promise.allSettled/Promise.resolve/Promise.reject 等靜態方法,差異(yi)點(dian)見下(xia)表:

方法 核心作用 狀態觸發條件 返回值格式 適用場景
Promise.race 多個 Promise 競爭,取第一個完成的結果 任意一個 Promise 改變狀態(fulfilled/rejected),立即觸發對應狀態 單個值(第一個 Promise 的 value/reason) 超時控制、請求降級
Promise.all 等待所有 Promise 成功,取全部結果 所有 Promise 都 fulfilled,才觸發 fulfilled;任意一個 rejected,立即觸發 rejected 數組(按原數組順序排列的所有 value) 并行請求多個無依賴接口(如加載頁面資源)
Promise.allSettled 等待所有 Promise 完成,取全部結果(無論成敗) 所有 Promise 都改變狀態(fulfilled/rejected),才觸發 fulfilled 數組(每個元素含 status 和 value/reason) 需知道所有請求結果(如批量操作日志)
Promise.resolve 快速創建一個 fulfilled 狀態的 Promise 無(直接返回 fulfilled 狀態的 Promise) 單個 value(參數值,或參數 Promise 的 value) 統一 Promise 格式、轉換同步值為異步
Promise.reject 快速創建一個 rejected 狀態的 Promise 無(直接返回 rejected 狀態的 Promise) 單個 reason(參數值) 快速拋出異步錯誤

與 async/await 的關系

async/await 本(ben)質是(shi) Promise 的語法(fa)糖。

  • async 函數:修飾的函數返回值必然是 Promise(若 return 非 Promise 值,會用Promise.resolve()包裝)
  • await 關鍵字:本質是 “等待 Promise 狀態變化” 的語法糖,只能在 async 函數內部使用,后面跟 Promise 對象,會暫停 async 函數執行,直到 Promise 狀態轉為fulfilled,并將value作為 await 表達式的結果,如果 Promise 狀態轉為rejected,會拋出錯誤,需用try/catch捕獲(等價于 Promise 的catch)。

面試追問

  1. 知道定(ding)義(yi),能手寫(xie)一(yi)個(ge) Promise.race 方法嗎?

    /**
     * 手寫Promise.race
     * @param {Iterable} iterable - 可迭代對象(如數組)
     * @returns {Promise} - 新的Promise對象
     */
    function myPromiseRace(iterable) {
      // 1. 邊界處理:參數必須是可迭代對象(檢查是否有Symbol.iterator方法)
      if (typeof iterable[Symbol.iterator] !== 'function') {
        return new Promise((_, reject) => {
          reject(new TypeError('Promise.race() 參數必須是可迭代對象'));
        });
      }
    
      // 2. 返回新Promise
      return new Promise((resolve, reject) => {
        // 3. 遍歷可迭代對象(用for...of兼容所有可迭代對象)
        for (const item of iterable) {
          // 4. 用Promise.resolve包裝item,處理非Promise元素
          Promise.resolve(item)
            .then((value) => {
              // 一旦有元素成功,立即resolve新Promise(后續元素不再處理)
              resolve(value);
            })
            .catch((reason) => {
              // 一旦有元素失敗,立即reject新Promise(后續元素不再處理)
              reject(reason);
            });
        }
      });
    }
    
  2. Promise 還有什么方法?有什么差異?
    參考擴展延伸部分

  3. 一個 Promise 可以多次 resolve 嗎?
    可以多次(ci)(ci)執(zhi)(zhi)行(xing) resolve 或(huo) reject,但(dan)是(shi)(shi) Promise 的(de)狀態只會改(gai)變一次(ci)(ci),就是(shi)(shi)第一次(ci)(ci)執(zhi)(zhi)行(xing) resolve的(de)時候,后續雖(sui)然會執(zhi)(zhi)行(xing) resolve,但(dan)是(shi)(shi)不影響(xiang)狀態,沒有作用。

  4. 用 Promise.race 實現超時控制時,若超時后原請求仍在繼續,會有什么問題?如何解決?
    出現資源浪費(fei),Promise.race 僅感知超時(shi)并返回(hui)結(jie)果,但是原請(qing)求依(yi)舊會(hui)繼(ji)續(xu)執(zhi)行(xing),可以結(jie)合axios的CancelToken或AbortController取消請(qing)求去中斷。

  5. 如何用 Promise 實現‘重(zhong)試機制’?比(bi)如接口請求失敗(bai)后(hou),重(zhong)試 3 次(ci)(ci),每(mei)次(ci)(ci)間隔(ge) 2 秒。

    /**
     * Promise重試機制
     * @param {Function} requestFn - 請求函數(返回Promise)
     * @param {number} maxRetry - 最大重試次數
     * @param {number} interval - 重試間隔(毫秒)
     * @param {number} currentRetry - 當前重試計數(默認0,內部使用)
     * @returns {Promise} - 最終請求結果
     */
    function promiseRetry(requestFn, maxRetry = 3, interval = 2000, currentRetry = 0) {
      return new Promise((resolve, reject) => {
        requestFn()
          .then(resolve) // 請求成功,直接返回結果
          .catch((err) => {
            // 若已達最大重試次數,拋出最終錯誤
            if (currentRetry >= maxRetry) {
              reject(new Error(`重試${maxRetry}次后仍失敗:${err.message}`));
              return;
            }
    
            // 未達最大次數,延遲后重試
            console.log(`請求失敗,${interval}ms后重試(第${currentRetry+1}次)`);
            setTimeout(() => {
              // 遞歸調用,當前重試計數+1
              promiseRetry(requestFn, maxRetry, interval, currentRetry + 1)
                .then(resolve)
                .catch(reject);
            }, interval);
          });
      });
    }
    
    // 調用示例:請求失敗后重試3次,每次間隔2秒
    const fetchData = () => {
      // 模擬接口請求(50%概率失敗)
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (Math.random() > 0.5) {
            resolve('請求成功結果');
          } else {
            reject(new Error('接口返回錯誤'));
          }
        }, 1000);
      });
    };
    
    promiseRetry(fetchData, 3, 2000)
      .then((res) => console.log('最終結果:', res))
      .catch((err) => console.log('最終失敗:', err.message));
    
posted @ 2025-10-29 11:02  Achieve前端實驗室  閱讀(100)  評論(0)    收藏  舉報