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

js進(jìn)階教程之promise全方位解析和異步編程

 更新時(shí)間:2025年10月06日 09:36:29   作者:橫木沉  
Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案(回調(diào)函數(shù)和事件)更合理和更強(qiáng)大,下面這篇文章主要介紹了js進(jìn)階教程之promise全方位解析和異步編程的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

Promise 是 JavaScript 異步編程的核心解決方案,也是前端工程師進(jìn)階必備的核心知識(shí)點(diǎn)。本文將全方位介紹 Promise,涵蓋從基礎(chǔ)概念到高級(jí)應(yīng)用,再到面試實(shí)戰(zhàn)的全鏈路知識(shí)。

一、Promises/A+ 規(guī)范基礎(chǔ)

1. Promise 的狀態(tài)

Promise 是一個(gè)??狀態(tài)機(jī)??,有且僅有三種狀態(tài):

  • ??pending(等待中)??:初始狀態(tài),既不是成功也不是失敗。
  • ??fulfilled(已成功)??:操作成功完成,通過(guò) resolve()觸發(fā)。
  • ??rejected(已失?。??:操作失敗,通過(guò) reject()觸發(fā)。

?? ??狀態(tài)不可逆??:一旦從 pending 變?yōu)?fulfilled 或 rejected,狀態(tài)將永久固定,不可再次改變。

2. then 方法:核心機(jī)制

then是 Promise 的核心方法,用于注冊(cè)狀態(tài)變更后的回調(diào)函數(shù):

  • ??接收兩個(gè)回調(diào)??:
    • 第一個(gè)參數(shù):onFulfilled(狀態(tài)變?yōu)?fulfilled 時(shí)執(zhí)行)。
    • 第二個(gè)參數(shù):onRejected(狀態(tài)變?yōu)?rejected 時(shí)執(zhí)行,可選)。
  • ?回調(diào)返回值?
    • 若回調(diào)返回普通值(非 Promise),則新 Promise 以該值 fulfilled。

    • 若回調(diào)拋出異常,則新 Promise 以該異常 rejected。
    • 若回調(diào)返回另一個(gè) Promise,則當(dāng)前 Promise 會(huì)??跟隨該返回 Promise 的狀態(tài)??(鏈?zhǔn)秸{(diào)用的核心)。
const p = new Promise((resolve) => resolve(10));

p.then(
  (value) => {
    console.log(value); // 10(onFulfilled 回調(diào))
    return value * 2;   // 返回普通值 → 新 Promise 以 20 fulfilled
  },
  (err) => console.error(err) // 不會(huì)執(zhí)行(原 Promise 未失?。?
).then((newValue) => {
  console.log(newValue); // 20(跟隨返回的隱式 Promise)
});

3. Promise 解析過(guò)程(核心機(jī)制)

當(dāng) then的回調(diào)返回一個(gè) ??新的 Promise(記作 P)?? 時(shí),當(dāng)前 Promise 會(huì)暫停自身的狀態(tài)變更,轉(zhuǎn)而??監(jiān)聽(tīng) P 的狀態(tài)??:

  • 若 P 變?yōu)?fulfilled,則當(dāng)前 Promise 以 P 的結(jié)果 fulfilled;
  • 若 P 變?yōu)?rejected,則當(dāng)前 Promise 以 P 的錯(cuò)誤 rejected。

?? ??鏈?zhǔn)秸{(diào)用的本質(zhì)??:通過(guò)解析過(guò)程實(shí)現(xiàn)多個(gè)異步操作的依次執(zhí)行(前一個(gè)操作的結(jié)果作為下一個(gè)操作的輸入)。

二、傳統(tǒng)異步任務(wù)處理的痛點(diǎn)

1. 回調(diào)函數(shù)模式

早期 JavaScript 通過(guò)嵌套回調(diào)處理異步(例如 AJAX 請(qǐng)求):

getData(function(result1) {
  processResult1(result1, function(result2) {
    saveResult2(result2, function(result3) {
      // 嵌套層級(jí)加深 → 代碼難以維護(hù)
    });
  });
});

2. 回調(diào)地獄(Callback Hell)

多層嵌套回調(diào)會(huì)導(dǎo)致代碼橫向擴(kuò)展(縮進(jìn)層級(jí)過(guò)深),出現(xiàn)“金字塔”結(jié)構(gòu)的代碼,可讀性差、錯(cuò)誤處理困難、難以復(fù)用邏輯。

?? ??Promise 的誕生??:為了解決回調(diào)地獄問(wèn)題,提供更扁平化的異步代碼組織方式。

三、Promise 詳解

1. 什么是 Promise?

  • ??本質(zhì)??:一個(gè)構(gòu)造函數(shù)(類(lèi)),通過(guò) new Promise(executor)實(shí)例化。
  • 核心機(jī)制??:
    • executor 是一個(gè)同步執(zhí)行的回調(diào)函數(shù),接收兩個(gè)參數(shù):resolve(標(biāo)記成功)和 reject(標(biāo)記失?。?。
    • Promise 內(nèi)部通過(guò)狀態(tài)機(jī)管理異步操作的結(jié)果,外部通過(guò) then/catch/finally監(jiān)聽(tīng)狀態(tài)變更。
const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('異步操作成功'), 1000); // 1秒后標(biāo)記成功
});

2. resolve 的參數(shù)規(guī)則

resolve可接受多種類(lèi)型的參數(shù),處理邏輯不同:

參數(shù)類(lèi)型

行為

普通值(如字符串、數(shù)字)

當(dāng)前 Promise 以該值 fulfilled。

另一個(gè) Promise

當(dāng)前 Promise 會(huì)跟隨該 Promise 的狀態(tài)(鏈?zhǔn)秸{(diào)用的基礎(chǔ))。

Thenable 對(duì)象(含 then 方法的對(duì)象)

會(huì)嘗試調(diào)用其 then 方法,將其轉(zhuǎn)換為標(biāo)準(zhǔn) Promise 行為。

// 示例 1:普通值
Promise.resolve(42).then(v => console.log(v)); // 42

// 示例 2:返回另一個(gè) Promise
Promise.resolve(Promise.resolve('嵌套 Promise')).then(v => console.log(v)); // 嵌套 Promise

// 示例 3:Thenable 對(duì)象
const thenable = { then(resolve) { resolve('Thenable 轉(zhuǎn)換成功'); } };
Promise.resolve(thenable).then(v => console.log(v)); // Thenable 轉(zhuǎn)換成功

3. Promise 的實(shí)例方法

(1) then 方法

  • ??參數(shù)??:onFulfilled(成功回調(diào),可選)、onRejected(失敗回調(diào),可選)。
  • ??返回值??:一個(gè)新的 Promise(支持鏈?zhǔn)秸{(diào)用)。
  • ??回調(diào)返回值??:決定新 Promise 的狀態(tài)(如返回普通值、Promise 或拋出異常)。
Promise.resolve(1)
  .then(val => val + 1) // 返回普通值 2 → 新 Promise 以 2 fulfilled
  .then(val => console.log(val)); // 2

(2) 多次調(diào)用 then

  • 每次調(diào)用 then都會(huì)注冊(cè)新的回調(diào),??按注冊(cè)順序依次執(zhí)行??(即使前一個(gè)回調(diào)異步延遲)。
  • 多個(gè) then可以分別處理同一 Promise 的成功狀態(tài)。
const p = Promise.resolve(10);
p.then(v => console.log(v)); // 10
p.then(v => console.log(v + 5)); // 15

(3) catch 方法

  • ??作用??:專(zhuān)門(mén)捕獲 Promise 鏈中的錯(cuò)誤(相當(dāng)于 then(null, onRejected))。
  • ??參數(shù)??:錯(cuò)誤處理回調(diào)(接收錯(cuò)誤對(duì)象)。
  • ??特性??:可捕獲當(dāng)前 Promise 或鏈中上游未處理的 rejected 狀態(tài)。
Promise.reject(new Error('操作失敗'))
  .catch(err => console.error('捕獲錯(cuò)誤:', err.message)); // 捕獲錯(cuò)誤: 操作失敗

(4) finally 方法

  • ??作用??:無(wú)論 Promise 成功或失敗,都會(huì)執(zhí)行的清理邏輯(如關(guān)閉加載動(dòng)畫(huà))。
  • ??參數(shù)??:無(wú)參數(shù)回調(diào)(無(wú)法獲取 Promise 的結(jié)果或錯(cuò)誤)。
  • ??特性??:不會(huì)改變?cè)?Promise 的狀態(tài)或結(jié)果。
Promise.resolve('成功')
  .finally(() => console.log('無(wú)論如何都會(huì)執(zhí)行')) // 無(wú)論如何都會(huì)執(zhí)行
  .then(v => console.log(v)); // 成功

4. Promise 的類(lèi)方法

(1) Promise.resolve / Promise.reject

  • ??作用??:快速創(chuàng)建已 resolved/rejected 的 Promise。
  • ??參數(shù)??:與 resolve/reject方法一致。
Promise.resolve('直接成功').then(v => console.log(v)); // 直接成功
Promise.reject('直接失敗').catch(e => console.error(e)); // 直接失敗

(2) Promise.all

  • ??作用??:并行執(zhí)行多個(gè) Promise,??全部成功時(shí)返回結(jié)果數(shù)組??,??任一失敗立即 rejected??。
  • ??參數(shù)??:Promise 數(shù)組。
  • 適用場(chǎng)景??:同時(shí)發(fā)起多個(gè)獨(dú)立異步請(qǐng)求,需全部完成后再處理結(jié)果。
Promise.all([
  Promise.resolve(1),
  Promise.resolve(2),
]).then(([res1, res2]) => console.log(res1, res2)); // 1 2

Promise.all([
  Promise.resolve(1),
  Promise.reject('失敗'),
]).catch(e => console.error(e)); // 失敗

(3) Promise.allSettled

  • 作用??:并行執(zhí)行多個(gè) Promise,??等待所有完成(無(wú)論成功/失?。??,返回每個(gè) Promise 的狀態(tài)和結(jié)果。
  • ??參數(shù)??:Promise 數(shù)組。
  • ??適用場(chǎng)景??:需要知道所有異步操作的最終狀態(tài)(如批量提交后統(tǒng)計(jì)成功/失敗數(shù)量)。
Promise.allSettled([
  Promise.resolve(1),
  Promise.reject('失敗'),
]).then(results => {
  results.forEach(r => console.log(r.status, r.value || r.reason));
  // fulfilled 1
  // rejected 失敗
});

(4) Promise.race

  • ??作用??:并行執(zhí)行多個(gè) Promise,??返回第一個(gè) settled(成功/失?。┑?Promise 結(jié)果??。
  • ??參數(shù)??:Promise 數(shù)組。
  • 適用場(chǎng)景??:超時(shí)控制(如請(qǐng)求超時(shí)后取消操作)。
Promise.race([
  Promise.resolve('快的'),
  new Promise(resolve => setTimeout(() => resolve('慢的'), 1000)),
]).then(v => console.log(v)); // 快的

(5) Promise.any

  • ??作用??:并行執(zhí)行多個(gè) Promise,??返回第一個(gè)成功的 Promise 結(jié)果??,??全部失敗時(shí)拋出 AggregateError??。
  • ??參數(shù)??:Promise 數(shù)組。
  • ??適用場(chǎng)景??:多備用數(shù)據(jù)源(如主接口失敗后嘗試備用接口)。
Promise.any([
  Promise.reject('失敗1'),
  Promise.resolve('成功'),
]).then(v => console.log(v)); // 成功

四、手寫(xiě) Promise 實(shí)現(xiàn)(核心邏輯)

手寫(xiě) Promise 是深入理解其原理的最佳方式,需實(shí)現(xiàn)以下核心方法(可通過(guò) Jest 編寫(xiě)單元測(cè)試驗(yàn)證):

  • ??構(gòu)造函數(shù)(constructor)??:接收 executor,管理狀態(tài)和結(jié)果。
  • ??then/catch/finally??:注冊(cè)回調(diào)并處理鏈?zhǔn)秸{(diào)用。
  • 類(lèi)方法(resolve/reject/all/allSettled/race/any)??:靜態(tài)工具方法。

?? ??關(guān)鍵點(diǎn)??:狀態(tài)不可逆、then 的鏈?zhǔn)秸{(diào)用(返回新 Promise)、異步執(zhí)行回調(diào)(通過(guò)微任務(wù)隊(duì)列,如 queueMicrotask)。

下面是一個(gè)完整的手寫(xiě) Promise 實(shí)現(xiàn)(支持 Promises/A+ 規(guī)范),包含核心方法(constructor、then、catch、finally)及靜態(tài)方法(resolve、reject、all、allSettled、race、any),并附帶對(duì)應(yīng)的 Jest 單元測(cè)試代碼。

1.Promise 實(shí)現(xiàn) (myPromise.js)

// 定義 Promise 的三種狀態(tài)
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    this.state = PENDING; // 初始狀態(tài)為 pending
    this.value = undefined; // 成功時(shí)的值
    this.reason = undefined; // 失敗時(shí)的原因
    this.onFulfilledCallbacks = []; // 成功的回調(diào)隊(duì)列
    this.onRejectedCallbacks = []; // 失敗的回調(diào)隊(duì)列

    // 定義 resolve 函數(shù)
    const resolve = (value) => {
      // 只有 pending 狀態(tài)可以改變
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.value = value;
        // 執(zhí)行所有成功的回調(diào)
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };

    // 定義 reject 函數(shù)
    const reject = (reason) => {
      // 只有 pending 狀態(tài)可以改變
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.reason = reason;
        // 執(zhí)行所有失敗的回調(diào)
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };

    try {
      // 立即執(zhí)行 executor
      executor(resolve, reject);
    } catch (error) {
      // 如果 executor 執(zhí)行出錯(cuò),直接 reject
      reject(error);
    }
  }

  // then 方法
  then(onFulfilled, onRejected) {
    // 處理 then 的參數(shù)不是函數(shù)的情況
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };

    // 返回一個(gè)新的 Promise 以實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用
    const promise2 = new MyPromise((resolve, reject) => {
      // 如果狀態(tài)是 fulfilled
      if (this.state === FULFILLED) {
        // 使用 setTimeout 模擬微任務(wù)
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            // 解析 promise2 和 x 的關(guān)系
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.state === REJECTED) {
        // 如果狀態(tài)是 rejected
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            // 解析 promise2 和 x 的關(guān)系
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.state === PENDING) {
        // 如果狀態(tài)是 pending,將回調(diào)函數(shù)存入隊(duì)列
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });

    return promise2;
  }

  // 解析 promise 和 x 的關(guān)系
  resolvePromise(promise2, x, resolve, reject) {
    // 如果 promise2 和 x 是同一個(gè)對(duì)象,拋出 TypeError
    if (promise2 === x) {
      return reject(new TypeError('Chaining cycle detected for promise'));
    }

    // 如果 x 是一個(gè) Promise
    if (x instanceof MyPromise) {
      x.then(resolve, reject);
    } else {
      // 如果 x 是一個(gè)普通值
      resolve(x);
    }
  }

  // catch 方法
  catch(onRejected) {
    return this.then(null, onRejected);
  }

  // finally 方法
  finally(callback) {
    return this.then(
      value => MyPromise.resolve(callback()).then(() => value),
      reason => MyPromise.resolve(callback()).then(() => { throw reason; })
    );
  }

  // 靜態(tài) resolve 方法
  static resolve(value) {
    // 如果 value 是一個(gè) Promise,直接返回
    if (value instanceof MyPromise) {
      return value;
    }
    // 否則返回一個(gè)新的 resolved Promise
    return new MyPromise(resolve => resolve(value));
  }

  // 靜態(tài) reject 方法
  static reject(reason) {
    return new MyPromise((_, reject) => reject(reason));
  }

  // 靜態(tài) all 方法
  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const results = [];
      let completed = 0;
      const promiseCount = promises.length;

      if (promiseCount === 0) {
        resolve(results);
        return;
      }

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          value => {
            results[index] = value;
            completed++;
            if (completed === promiseCount) {
              resolve(results);
            }
          },
          reason => {
            reject(reason);
          }
        );
      });
    });
  }

  // 靜態(tài) allSettled 方法
  static allSettled(promises) {
    return new MyPromise((resolve) => {
      const results = [];
      let completed = 0;
      const promiseCount = promises.length;

      if (promiseCount === 0) {
        resolve(results);
        return;
      }

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          value => {
            results[index] = { status: FULFILLED, value };
            completed++;
            if (completed === promiseCount) {
              resolve(results);
            }
          },
          reason => {
            results[index] = { status: REJECTED, reason };
            completed++;
            if (completed === promiseCount) {
              resolve(results);
            }
          }
        );
      });
    });
  }

  // 靜態(tài) race 方法
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach(promise => {
        MyPromise.resolve(promise).then(resolve, reject);
      });
    });
  }

  // 靜態(tài) any 方法
  static any(promises) {
    return new MyPromise((resolve, reject) => {
      const errors = [];
      let rejectedCount = 0;
      const promiseCount = promises.length;

      if (promiseCount === 0) {
        reject(new AggregateError(errors, 'All promises were rejected'));
        return;
      }

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          value => {
            resolve(value);
          },
          reason => {
            errors[index] = reason;
            rejectedCount++;
            if (rejectedCount === promiseCount) {
              reject(new AggregateError(errors, 'All promises were rejected'));
            }
          }
        );
      });
    });
  }
}

module.exports = MyPromise;

2.Jest 單元測(cè)試 (myPromise.test.js)

const MyPromise = require('./myPromise');

describe('MyPromise', () => {
  // 測(cè)試構(gòu)造函數(shù)和基本功能
  describe('Constructor', () => {
    test('should execute executor immediately', () => {
      let executed = false;
      new MyPromise(() => {
        executed = true;
      });
      expect(executed).toBe(true);
    });

    test('should handle resolve in executor', (done) => {
      new MyPromise((resolve) => {
        resolve('success');
      }).then((value) => {
        expect(value).toBe('success');
        done();
      });
    });

    test('should handle reject in executor', (done) => {
      new MyPromise((_, reject) => {
        reject('error');
      }).catch((reason) => {
        expect(reason).toBe('error');
        done();
      });
    });

    test('should catch executor errors', (done) => {
      new MyPromise(() => {
        throw new Error('executor error');
      }).catch((error) => {
        expect(error.message).toBe('executor error');
        done();
      });
    });
  });

  // 測(cè)試 then 方法
  describe('then', () => {
    test('should handle fulfilled promise', (done) => {
      new MyPromise((resolve) => {
        resolve('fulfilled');
      }).then((value) => {
        expect(value).toBe('fulfilled');
        done();
      });
    });

    test('should handle rejected promise', (done) => {
      new MyPromise((_, reject) => {
        reject('rejected');
      }).then(null, (reason) => {
        expect(reason).toBe('rejected');
        done();
      });
    });

    test('should chain then calls', (done) => {
      new MyPromise((resolve) => {
        resolve(1);
      })
        .then((value) => {
          expect(value).toBe(1);
          return value + 1;
        })
        .then((value) => {
          expect(value).toBe(2);
          return value + 1;
        })
        .then((value) => {
          expect(value).toBe(3);
          done();
        });
    });

    test('should handle async then callbacks', (done) => {
      let first = false;
      new MyPromise((resolve) => {
        resolve(1);
      })
        .then((value) => {
          first = true;
          return value + 1;
        })
        .then((value) => {
          expect(first).toBe(true);
          expect(value).toBe(2);
          done();
        });
    });

    test('should use default onFulfilled if not a function', (done) => {
      new MyPromise((resolve) => {
        resolve(1);
      }).then(null).then((value) => {
        expect(value).toBe(1);
        done();
      });
    });

    test('should use default onRejected if not a function', (done) => {
      new MyPromise((_, reject) => {
        reject(1);
      }).then(null, null).catch((reason) => {
        expect(reason).toBe(1);
        done();
      });
    });
  });

  // 測(cè)試 catch 方法
  describe('catch', () => {
    test('should catch rejected promise', (done) => {
      new MyPromise((_, reject) => {
        reject('error');
      }).catch((reason) => {
        expect(reason).toBe('error');
        done();
      });
    });

    test('should chain catch calls', (done) => {
      new MyPromise((_, reject) => {
        reject('first error');
      })
        .catch((reason) => {
          expect(reason).toBe('first error');
          return 'recovered';
        })
        .then((value) => {
          expect(value).toBe('recovered');
          done();
        });
    });
  });

  // 測(cè)試 finally 方法
  describe('finally', () => {
    test('should execute finally callback', (done) => {
      let called = false;
      new MyPromise((resolve) => {
        resolve('value');
      })
        .finally(() => {
          called = true;
        })
        .then((value) => {
          expect(called).toBe(true);
          expect(value).toBe('value');
          done();
        });
    });

    test('should pass through value', (done) => {
      new MyPromise((resolve) => {
        resolve('value');
      })
        .finally(() => {})
        .then((value) => {
          expect(value).toBe('value');
          done();
        });
    });

    test('should pass through reason', (done) => {
      new MyPromise((_, reject) => {
        reject('reason');
      })
        .finally(() => {})
        .catch((reason) => {
          expect(reason).toBe('reason');
          done();
        });
    });

    test('should handle finally callback with return value', (done) => {
      new MyPromise((resolve) => {
        resolve(1);
      })
        .finally(() => {
          return 2;
        })
        .then((value) => {
          expect(value).toBe(1);
          done();
        });
    });

    test('should handle finally callback with promise', (done) => {
      new MyPromise((resolve) => {
        resolve(1);
      })
        .finally(() => {
          return new MyPromise((resolve) => {
            resolve(2);
          });
        })
        .then((value) => {
          expect(value).toBe(1);
          done();
        });
    });
  });

  // 測(cè)試靜態(tài)方法 resolve
  describe('static resolve', () => {
    test('should resolve with a value', (done) => {
      MyPromise.resolve('value').then((value) => {
        expect(value).toBe('value');
        done();
      });
    });

    test('should resolve with a promise', (done) => {
      const p = new MyPromise((resolve) => {
        resolve('promise value');
      });
      MyPromise.resolve(p).then((value) => {
        expect(value).toBe('promise value');
        done();
      });
    });
  });

  // 測(cè)試靜態(tài)方法 reject
  describe('static reject', () => {
    test('should reject with a reason', (done) => {
      MyPromise.reject('reason').catch((reason) => {
        expect(reason).toBe('reason');
        done();
      });
    });
  });

  // 測(cè)試靜態(tài)方法 all
  describe('static all', () => {
    test('should resolve with an array of values', (done) => {
      const p1 = MyPromise.resolve(1);
      const p2 = MyPromise.resolve(2);
      const p3 = MyPromise.resolve(3);

      MyPromise.all([p1, p2, p3]).then((values) => {
        expect(values).toEqual([1, 2, 3]);
        done();
      });
    });

    test('should reject if any promise rejects', (done) => {
      const p1 = MyPromise.resolve(1);
      const p2 = MyPromise.reject('error');
      const p3 = MyPromise.resolve(3);

      MyPromise.all([p1, p2, p3]).catch((reason) => {
        expect(reason).toBe('error');
        done();
      });
    });

    test('should resolve with empty array', (done) => {
      MyPromise.all([]).then((values) => {
        expect(values).toEqual([]);
        done();
      });
    });
  });

  // 測(cè)試靜態(tài)方法 allSettled
  describe('static allSettled', () => {
    test('should resolve with all settled results', (done) => {
      const p1 = MyPromise.resolve(1);
      const p2 = MyPromise.reject('error');
      const p3 = MyPromise.resolve(3);

      MyPromise.allSettled([p1, p2, p3]).then((results) => {
        expect(results).toEqual([
          { status: 'fulfilled', value: 1 },
          { status: 'rejected', reason: 'error' },
          { status: 'fulfilled', value: 3 }
        ]);
        done();
      });
    });

    test('should resolve with empty array', (done) => {
      MyPromise.allSettled([]).then((results) => {
        expect(results).toEqual([]);
        done();
      });
    });
  });

  // 測(cè)試靜態(tài)方法 race
  describe('static race', () => {
    test('should resolve with the first resolved promise', (done) => {
      const p1 = new MyPromise((resolve) => {
        setTimeout(() => resolve(1), 100);
      });
      const p2 = MyPromise.resolve(2);

      MyPromise.race([p1, p2]).then((value) => {
        expect(value).toBe(2);
        done();
      });
    });

    test('should reject with the first rejected promise', (done) => {
      const p1 = new MyPromise((_, reject) => {
        setTimeout(() => reject('error'), 100);
      });
      const p2 = MyPromise.reject('quick error');

      MyPromise.race([p1, p2]).catch((reason) => {
        expect(reason).toBe('quick error');
        done();
      });
    });
  });

  // 測(cè)試靜態(tài)方法 any
  describe('static any', () => {
    test('should resolve with the first resolved promise', (done) => {
      const p1 = new MyPromise((resolve) => {
        setTimeout(() => resolve(1), 100);
      });
      const p2 = MyPromise.resolve(2);

      MyPromise.any([p1, p2]).then((value) => {
        expect(value).toBe(2);
        done();
      });
    });

    test('should reject with all rejected promises if all are rejected', (done) => {
      const p1 = MyPromise.reject('error1');
      const p2 = MyPromise.reject('error2');

      MyPromise.any([p1, p2]).catch((error) => {
        expect(error.errors).toEqual(['error1', 'error2']);
        expect(error.message).toBe('All promises were rejected');
        done();
      });
    });

    test('should reject with AggregateError if all are rejected', (done) => {
      const p1 = MyPromise.reject('error1');
      const p2 = MyPromise.reject('error2');

      MyPromise.any([p1, p2]).catch((error) => {
        expect(error instanceof Error).toBe(true);
        expect(error.message).toBe('All promises were rejected');
        // 注意:這里簡(jiǎn)化了 AggregateError 的實(shí)現(xiàn),實(shí)際可能需要更復(fù)雜的檢查
        done();
      });
    });
  });
});

使用說(shuō)明

  1. 將 Promise 實(shí)現(xiàn)代碼保存為 myPromise.js
  2. 將測(cè)試代碼保存為 myPromise.test.js
  3. 確保已安裝 Jest (npm install --save-dev jest)
  4. 在 package.json 中添加測(cè)試腳本:
"scripts": {
  "test": "jest"
}

      5. 運(yùn)行測(cè)試:npm test

實(shí)現(xiàn)說(shuō)明

這個(gè) Promise 實(shí)現(xiàn)包含了以下特性:

  1. 基本功能??:
    • 三種狀態(tài):pending、fulfilled、rejected
    • 構(gòu)造函數(shù)接收 executor 函數(shù)
    • 異步執(zhí)行回調(diào)(使用 setTimeout 模擬微任務(wù))
  2. 實(shí)例方法??:
    • then(): 支持鏈?zhǔn)秸{(diào)用,處理成功和失敗情況
    • catch(): 捕獲錯(cuò)誤
    • finally(): 無(wú)論成功失敗都會(huì)執(zhí)行
  3. ??靜態(tài)方法??:
    • resolve(): 創(chuàng)建一個(gè)已解決的 Promise
    • reject(): 創(chuàng)建一個(gè)已拒絕的 Promise
    • all(): 所有 Promise 都成功時(shí)返回結(jié)果數(shù)組
    • allSettled(): 所有 Promise 都完成后返回結(jié)果狀態(tài)數(shù)組
    • race(): 返回第一個(gè)完成的 Promise 結(jié)果
    • any(): 返回第一個(gè)成功的 Promise,或所有都失敗時(shí)拋出錯(cuò)誤

五、async/await 介紹

1. 特點(diǎn)

  • ??語(yǔ)法糖??:基于 Promise 的語(yǔ)法糖,讓異步代碼看起來(lái)像同步代碼。
  • 本質(zhì)??:async函數(shù)返回 Promise,await用于暫停執(zhí)行直到 Promise 完成。

2. 用法

async function fetchData() {
  try {
    const result = await Promise.resolve('異步數(shù)據(jù)'); // 等待 Promise 完成
    console.log(result); // 異步數(shù)據(jù)
  } catch (err) {
    console.error(err);
  }
}
fetchData();

3. 適用場(chǎng)景

  • 需要按順序執(zhí)行多個(gè)異步操作(如先請(qǐng)求用戶(hù)信息,再請(qǐng)求訂單詳情)。
  • 替代復(fù)雜的 Promise 鏈(提升代碼可讀性)。

4. 與 Promise 對(duì)比

特性

async/await

Promise

代碼風(fēng)格

類(lèi)似同步代碼,更直觀(guān)

鏈?zhǔn)秸{(diào)用,需嵌套 then/catch

錯(cuò)誤處理

使用 try/catch

使用 catch 方法

可讀性

高(邏輯線(xiàn)性)

較低(嵌套層級(jí)深時(shí))

底層原理

基于 Promise

JavaScript 原生異步解決方案

六、Promise 相關(guān)面試題目

1. 經(jīng)典面試題:Promise 與事件循環(huán)

??題目??:分析以下代碼的輸出順序(結(jié)合宏任務(wù)與微任務(wù)):

console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');

解題思路??:

  1. 同步代碼優(yōu)先執(zhí)行??:輸出 1→ 4。
  2. ??微任務(wù)(Promise.then)??:在當(dāng)前宏任務(wù)結(jié)束后立即執(zhí)行,輸出 3。
  3. ??宏任務(wù)(setTimeout)??:在下一個(gè)事件循環(huán)中執(zhí)行,輸出 2。

??最終輸出順序??:1 → 4 → 3 → 2

2. 事件循環(huán)(宏任務(wù)與微任務(wù))

  • ??宏任務(wù)??:script 整體代碼、setTimeout、setInterval、I/O 操作。
  • ?微任務(wù)??:Promise.then/catch/finally、MutationObserver、queueMicrotask。

??執(zhí)行規(guī)則??:

  1. 執(zhí)行一個(gè)宏任務(wù)(如 script 代碼);
  2. 執(zhí)行該宏任務(wù)產(chǎn)生的所有微任務(wù);
  3. 渲染頁(yè)面(如有必要);
  4. 執(zhí)行下一個(gè)宏任務(wù)。

3. 解題思路總結(jié)

  • Promise 狀態(tài)機(jī)??:明確 pending → fulfilled/rejected 的不可逆性。
  • ??then 的鏈?zhǔn)秸{(diào)用??:每次 then 返回新 Promise,回調(diào)返回值決定新?tīng)顟B(tài)。
  • ??事件循環(huán)優(yōu)先級(jí)??:微任務(wù) > 宏任務(wù)(理解這一規(guī)則可解決 80% 的異步面試題)。

通過(guò)本文的全方位解析,你已掌握 Promise 的核心原理、實(shí)戰(zhàn)用法及面試要點(diǎn)。結(jié)合實(shí)際項(xiàng)目中的異步場(chǎng)景(如 API 請(qǐng)求、文件讀取),靈活運(yùn)用 Promise 和 async/await,可顯著提升代碼質(zhì)量和開(kāi)發(fā)效率! ??

到此這篇關(guān)于js進(jìn)階教程之promise全方位解析和異步編程的文章就介紹到這了,更多相關(guān)js promise解析和異步編程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論