Skip to content

Promise 概述与Promise 基本语法(Day17 1/3) ​

本页对应 Day17-Promise,共 6 段视频,约 1 小时 37 分。

学习目标 ​

  1. 能准确说明 Promise.all 的参数要求,并判断成员全部成功、存在失败、参数非可迭代对象时返回 Promise 的状态与结果。
  2. 能使用 Promise.all 配合 map 并发请求榜单歌曲详情,并按传入顺序将歌曲名称与演唱者渲染到页面。
  3. 能对比说明 Promise.all、Promise.race、Promise.allSettled 的返回值状态及结果规则,并针对给定场景选择正确方法。
  4. 能说明改变 Promise 状态的三种方式,并解释 then 返回的新 Promise 状态由回调函数的返回值或抛出的异常决定。
  5. 能解释 Promise 链式调用中的异常穿透与中断现象,并判断给定链式代码中各回调是否执行及执行顺序。

知识点 ​

从创建 Promise 说起:执行器与状态 ​

为什么需要:传统异步任务靠回调函数层层嵌套,顺序一乱就很难控制。Promise 用来把“等待结果”这件事对象化,后续才能用 then 链式处理。怎么想:new Promise(...) 传入的回调函数会立即执行,课堂里叫“执行器函数”;它接收 resolve 和 reject 两个函数。怎么做:调用 resolve 把状态改成成功(fulfilled),调用 reject 改成失败(rejected);谁先调用谁生效,状态一旦改变就不能再改。异步任务通常在拿到结果、定时器到点后才改状态。易错点:执行器是同步执行的,但 then/catch 注册的回调是异步的;不要以为 new Promise 完就立刻知道结果。

then、catch、finally 与返回值规则 ​

为什么需要:Promise 要替代回调写法,必须能分别处理成功和失败,还要能收尾。怎么想:then 可接两个回调,成功走第一个,失败走第二个;catch 只接失败回调;finally 只接一个回调,不管成功失败都会执行。怎么做:then 返回新的 Promise,其状态由回调返回值决定:无返回值→成功且 result 为 undefined;返回非 Promise 值→成功且 result 为该值;返回 Promise→接管该 Promise 的状态;抛异常→失败且 reason 为异常。catch 返回值规则同理。易错点:finally 不接收结果,不要拿它当 then 用;then 的第二个回调没写时,失败会继续往后传。

链式调用、异常穿透与中断 ​

为什么需要:多个异步任务要按顺序执行,比如上一步请求结果出来后才能发下一步。怎么想:then 返回新 Promise,所以可以 .then().then().catch() 串起来。怎么做:前面每层只写成功回调,最后用 catch 统一处理失败;前面某层失败且没被处理,会一路“穿透”到最后的 catch。调试时还演示了:中间某层返回一个状态永不改变的 Promise,整条链会卡住,后面都不执行。易错点:异常穿透不是“错误消失”,而是每层没写失败回调,失败状态继续往下传;链式调用中某一步不改变状态,就会中断后续。

静态方法 resolve 与 reject ​

为什么需要:快速创建已知状态的 Promise,避免每次手写 new Promise。怎么想:Promise.resolve 根据参数决定成功状态和 result;Promise.reject 一定得到失败状态。怎么做:resolve() 无参数→成功、result 为 undefined;传非 Promise 值→成功、result 为该值;传 Promise→原样返回;传 thenable 对象→用其 then 方法模拟。reject 无论传什么,参数都作为失败 reason。易错点:resolve 传 Promise 不是“再包一层”,而是直接返回它;reject 不会走成功。

Promise.all:全部成功才成功 ​

为什么需要:要同时发多个请求,并等它们全部成功后再统一处理,比如榜单前十首歌详情。怎么想:参数要求是可迭代对象(iterable),成员通常是 Promise;非 Promise 成员会用 Promise.resolve 转成 Promise。怎么做:返回一个 Promise;所有成员都成功,返回成功,result 是按“传入顺序”排列的结果数组;任一成员失败,立即失败,reason 是该失败成员的 reason;参数不是可迭代对象时直接失败。课堂调试:p4 用 setTimeout 3 秒后才 resolve(400),所以 Promise.all 要等所有成员状态改变才改变;结果数组中 400 仍按传入位置排列,不按完成顺序。易错点:all 是“全部成功”不是“全部完成”;结果顺序不是完成顺序;'hello world' 会被转成成功 Promise,而 100.25 不是 iterable,会失败并提示 number is not iterable。

Promise.race:谁先完成就听谁 ​

为什么需要:有时只关心最先返回的结果,比如超时竞争、多个源取最快。怎么想:参数规则同 all,但返回值采用“第一个完成”的成员。怎么做:Promise.race([p1, p4]) 中 p1 立即完成,就采用 p1 的状态和 result;如果 p1 是 reject,返回的也是失败,不管成功失败,先完成者胜。易错点:race 不是“最快成功”,而是“最快完成”;参数非可迭代对象同样失败。

Promise.allSettled:全部结果都记录 ​

为什么需要:有些场景不希望对失败“一刀切”,而是想知道每个任务最终成功还是失败。怎么想:它等所有成员完成,但自身通常总是成功。怎么做:返回 Promise,等全部成员状态改变后成功;result 数组按传入顺序对应每个成员,每项形如 {status:'fulfilled', value} 或 {status:'rejected', reason}。易错点:成员全失败时 allSettled 本身仍是成功;它不挑成功失败,只负责记录。

课堂问题总结 ​

不改变 Promise 状态时,then/catch 的回调不会执行;同一个 Promise 可以指定多个成功/失败回调,它们都会执行;then 返回的新 Promise 状态由返回值或异常决定;catch 可实现异常穿透;链式调用中某层状态不改变会中断后续。掌握这些规则后,再结合榜单案例:先取榜单列表,slice 取前十,map 成请求详情的 Promise 数组,交给 Promise.all,最后按传入顺序渲染歌曲名和歌手名。

一、Promise 解决什么问题 ​

为什么需要:传统异步任务常用回调函数层层嵌套,尤其是多个请求必须按顺序执行时,容易形成“回调地域”,错误处理也分散。Promise 是 ES6 新增的异步编程解决方案,用来更友好地组织异步流程。

怎么想:先创建一个 Promise 对象,把异步操作放进它的执行器函数里;异步成功后调用 resolve,失败后调用 reject,再用 then、catch 处理结果。

怎么做:

js
const p = new Promise((resolve, reject) => {
  // 异步操作
});

易错点:Promise 不是“自动帮你完成异步”,它只是统一管理异步状态和回调;执行器函数是 new Promise 时同步立即执行的,不是调用 then 时才执行。

二、创建 Promise 与执行器函数 ​

为什么需要:必须有一个地方启动异步操作,并决定成功或失败。

怎么想:new Promise 接收一个函数参数,这个函数通常叫执行器函数。它由 Promise 内部立即调用,并接收两个函数参数:第一个用于改成成功状态,第二个用于改成失败状态。

怎么做:

js
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(100);
  }, 3000);
});

易错点:执行器函数不是你手动调用的;两个参数名可以自定义,但习惯写 resolve、reject。真正改状态往往在拿到异步结果之后,例如请求返回、定时器到期。

三、三种状态与不可逆 ​

为什么需要:Promise 要明确表示异步任务当前处于什么阶段。

怎么想:Promise 对象有三种状态:pending(进行中)、resolved/fulfilled(已成功)、rejected(已失败)。刚创建时是 pending;调用第一个参数由 pending 变为成功,调用第二个参数由 pending 变为失败。

怎么做:

js
const p = new Promise((resolve, reject) => {
  resolve('成功');
  // reject('失败'); // 不会再改
});

易错点:状态一旦改变就再也不会变。转写稿里说“先下手为强”,即先调用哪个就先定哪个状态;后面再调用另一个也无效。抛出异常也会让 Promise 变成失败状态,但语法错误不属于这里讨论的运行时异常。

四、then、catch 与异步回调 ​

为什么需要:Promise 状态改变后,需要把成功或失败结果交给后续代码处理。

怎么想:then 可以设置成功和失败回调;catch 专门处理失败。状态改变后,对应回调才会执行。

怎么做:

js
p.then(
  value => console.log('成功', value),
  reason => console.log('失败', reason)
).catch(err => {
  console.log('捕获异常', err);
});

易错点:then、catch 设置的回调是异步执行的,不是同步立即执行;如果 Promise 状态一直不改变,回调就一直不执行。给同一个 Promise 直接设置多个成功回调,都会执行;链式中的 catch 处理的是前面返回的新 Promise。

五、链式调用与异常穿透 ​

为什么需要:多个异步任务要按顺序执行,链式调用可以避免回调嵌套。

怎么想:then 返回一个新的 Promise,所以可以继续 .then().then()。回调的返回值会影响新 Promise 的状态:没有返回值时成功且结果为 undefined;返回非 Promise 值时成功且结果为该值;返回 Promise 时跟随该 Promise 的状态;抛出异常时变为失败。

怎么做:

js
Promise.resolve(100)
  .then(v => v + 100)
  .then(v => v + 100)
  .catch(err => console.log(err));

易错点:中间某一步返回的 Promise 状态一直不改变,后面的链会卡住;前面只写成功回调时,失败会沿链“穿透”到最后的 catch。

六、Promise.all ​

为什么需要:经常要并发发起多个请求,并等全部成功后统一处理,例如榜单列表拿到歌曲 ID 后再查详情。

怎么想:参数要求是可迭代对象,成员通常是 Promise;非 Promise 成员会用 Promise.resolve 转成成功状态的 Promise。全部成员都成功,返回的 Promise 才成功,结果是数组,顺序按传入顺序,不按完成顺序;有一个失败就立即失败,结果是该失败原因。

怎么做:

js
Promise.all([p1, p2, p3])
  .then(list => console.log(list))
  .catch(err => console.log(err));

易错点:Promise.all 的结果顺序是传入顺序,不是谁先完成谁排前面;参数不是可迭代对象时,返回失败状态的 Promise。

七、Promise.race 与 Promise.allSettled ​

为什么需要:race 用于“谁先完成用谁”,allSettled 用于“无论成功失败都要汇总”。

怎么想:race 参数规则同 all,哪个成员先完成,不论成功还是失败,就直接作为返回结果。allSettled 等所有成员都完成,参数标准时返回的 Promise 一定成功,结果数组按传入顺序记录每项状态:成功为 { status: 'fulfilled', value },失败为 { status: 'rejected', reason }。

怎么做:

js
Promise.race([p1, p2]).then(v => console.log(v));
Promise.allSettled([p1, p2]).then(list => console.log(list));

易错点:race 看“先完成”,不是“先成功”;allSettled 中成员失败不会让返回 Promise 失败,除非参数本身不是可迭代对象。

一、创建 Promise 对象:先有容器 ​

为什么需要:异步任务的结果不会立刻拿到。Promise 的作用,是先创建一个“结果容器”,等异步任务完成后再把成功或失败的结果放进去,后续再注册回调处理。

怎么想:创建 Promise 要用 new Promise,并传入一个回调函数。这个回调函数在实例化时会被自动调用,转写稿里常把它叫“执行器函数”。它接收两个参数,而且这两个参数都是函数:第一个用来把状态改为成功,第二个用来把状态改为失败。

怎么做:先实例化,观察两个参数是什么:

js
 new Promise((res, rej) => {
     console.log('第一个参数:', res);
     console.log('第二个参数:', rej);
 });
js
1. 实例化 Promise 类,需要传一个回调函数作为参数
2. Promise 类的回调函数(参数),在实例化 Promise 的时候会自动调用,是同步任务
3. Promise 类的回调函数(参数),在被调用的时候,会接收两个参数,两个参数都是函数

调试时打印 res、rej 可以看到它们都是函数。这里要注意:执行器函数是 new Promise 时同步自动执行的,不是等 then 时才执行。

易错点:不要把“执行器自动执行”理解成“Promise 里的异步任务已经完成”;也不要把 res、rej 当成普通值,它们是函数。名字可以自定义,但第一个参数代表成功、第二个参数代表失败,这个顺序不能乱。

二、修改 Promise 对象的状态 ​

为什么需要:Promise 对象需要有一个状态,then 才能根据成功或失败决定执行哪个回调。刚创建时是等待状态,调用 resolve 或 reject 后状态才确定。

怎么想:调用执行器的第一个参数,状态改为 resolved(fulfilled);调用第二个参数,状态改为 rejected。传给它们的参数会作为 PromiseResult,也就是后续回调能拿到的结果。转写稿强调“先下手为强”:状态一旦改变,就不能再修改。

怎么做:

js
new Promise((resolve, reject) => {
    // 调用第一个参数 该promise对象的状态改为 resolved(fulfilled)
    // 可以传个参数作为 PromiseResult
    // resolve('hello');
    // resolve({status:'OK', msg: 'success'});

    // 调用第二个参数, 该promise对象的状态改为 rejected
    // 可以传个参数作为 PromiseResult
    // reject();
    reject([10,20,30,40]);
});
js
1. 调用 Promise 类回调函数的第一个参数,该 promise 对象改为 resolve(fulfilled)状态,可以传个参数作为 PromiseResult
2. 调用 Promise 类回调函数的第二个参数,该 promise 对象改为 rejected 状态,可以传个参数作为 PromiseResult
3. promise 对象的状态一旦改变,就无法再修改

易错点:不要同时调用 resolve 和 reject 还期待状态来回变;只有先调用的那个生效。也不要以为不调用它们会“自动成功”,如果不改变状态,Promise 会一直等待,后面的 then 回调不会执行。

三、用 then 为 Promise 对象设置回调 ​

为什么需要:状态改变后,需要一种方式接收结果。then 就是给 Promise 注册成功和失败回调的方法。

怎么想:then 的第一个参数是成功回调,状态变为成功时执行;第二个参数是失败回调,状态变为失败时执行。回调的形参可以拿到 PromiseResult。转写稿特别强调:then 的两个回调函数都是异步执行的。

怎么做:

js
promise对象.then(res => {
    // 如果promise对象是成功状态,执行该回调函数
    // res 可以获取 PromiseResult
}, err => {
    // 如果promise对象是失败状态,执行该回调函数
    // res 可以获取 PromiseResult
});
js
1. promise对象的then方法第第一个参数(回调函数),状态变为成功会执行,可以通过形参得到 PromiseResult
2. promise对象的then方法第第二个参数(回调函数),状态变为失败会执行,可以通过形参得到 PromiseResult
3. then 方法的两个回调函数都是异步执行!

易错点:then 回调不是同步执行的。即使执行器里立刻 resolve,then 里的回调也会异步执行;如果 Promise 状态一直不变,then 回调就一直不执行。另外,第二个回调的形参在示例注释里写成了 res,实际它接收的是失败原因,常命名为 err 或 reason,不要被注释误导。

课堂画面 ​

课堂画面 1

课堂画面 2

课堂画面 3

课堂画面 4

课堂画面 5

课堂画面 6

代码示例 ​

示例 1:Promise 基本语法 —— 创建、改状态、then 取结果 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>Promise 基本语法</title>
</head>
<body>
  <script>
    // ① 实例化 Promise:必须传一个回调函数(执行器函数)
    //    执行器函数在 new 的时候自动调用,是同步任务
    //    它会被动接收两个参数 resolve / reject,两个都是函数
    const p = new Promise((resolve, reject) => {
      console.log('执行器函数:new 的时候自动执行(同步)');

      // ② 调用第一个参数 → 状态改为 resolved(fulfilled)
      //    传的参数会作为 PromiseResult
      resolve({ status: 'OK', msg: 'success' });

      // 调用第二个参数 → 状态改为 rejected
      // reject([10, 20, 30, 40]);
      // 注意:先调用谁先生效,状态改了之后就再也不会变
    });

    // ③ 为 promise 对象设置回调函数
    p.then(
      res => {
        // 成功状态执行这里,res 就是 PromiseResult
        console.log('成功回调,拿到 PromiseResult:', res);
      },
      err => {
        // 失败状态执行这里,err 就是 PromiseResult
        console.log('失败回调,拿到 PromiseResult:', err);
      }
    );

    // then 的两个回调都是异步执行的,所以这行最先打印
    console.log('这行比 then 的回调先打印');
  </script>
</body>
</html>

要点与易错点

  • new Promise(回调) 里的回调在实例化时立即执行,是同步任务;但 .then(成功回调, 失败回调) 的两个回调都是异步执行的,所以上面控制台顺序是:执行器函数 → 最后一行 → 成功回调。
  • 改状态只有两条路:调用 resolve 改成功、调用 reject 改失败。状态一旦改变就再也不能修改,两个都调用时"先下手为强",谁先调用谁生效。
  • then 的第一个回调接收 PromiseResult(成功的结果),第二个回调接收失败的原因。写 reject([10,20,30,40]) 时,then 的第二个形参拿到的就是这个数组。
  • 易错点:不改变状态就永远不执行任何回调(没有 resolve 也没有 reject、也没抛异常,就"耗着"),不是"默认成功"。

示例 2:Promise.all / race / allSettled 三个静态方法对比 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>Promise 静态方法</title>
</head>
<body>
  <script>
    // 快速创建成功状态的 promise
    const p1 = Promise.resolve(100);
    const p2 = Promise.resolve(200);
    const p3 = Promise.resolve(300);

    // 需要等待 3 秒才改变状态
    const p4 = new Promise(resolve => {
      setTimeout(() => {
        resolve(400);
      }, 3000);
    });

    const p5 = Promise.resolve(500);

    // 可能成功、可能失败的成员
    const p6 = new Promise((resolve, reject) => {
      const rnd = Math.random();
      if (rnd >= 0.5) {
        resolve(rnd);   // 成功,结果是随机数
      } else {
        reject(rnd);    // 失败,原因是随机数
      }
    });

    // 参数:可迭代对象;成员不是 promise 也没事,会自动用 Promise.resolve 转换
    const arr = [p1, p2, p3, p4, p5, p6, 'hello world'];

    // ① Promise.all:都成功才成功,一个失败全盘结束
    Promise.all(arr).then(res => {
      console.log('all 成功:', res);
    }).catch(err => {
      console.log('all 失败:', err);
    });

    // ② Promise.race:谁先完成(不论成功失败)就是谁
    Promise.race(arr).then(res => {
      console.log('race 成功:', res);
    }).catch(err => {
      console.log('race 失败:', err);
    });

    // ③ Promise.allSettled:不挑,成功失败都记下来,自己一定是成功的
    Promise.allSettled(arr).then(res => {
      console.log('allSettled 结果:', res);
    });

    // 参数不是可迭代对象时,直接得到一个失败状态的 promise
    Promise.all(100).catch(err => {
      console.log('参数不合法:', err);
    });
  </script>
</body>
</html>

要点与易错点

  • Promise.all:所有成员都成功才成功,结果数组按传入顺序排列,不是完成顺序(p4 最晚改状态,但仍排第 4 位);只要有一个成员失败就立即失败,不再等其他成员,catch 拿到的是那个失败成员的 PromiseResult。
  • Promise.race:参数规则和 all 一样,返回值看哪个成员先完成,成功失败不论,谁先出结果就作为整个 promise 的返回值(这里 p1 立即完成,所以结果是 100)。
  • Promise.allSettled:返回值一定是成功状态(只要参数是可迭代对象),结果是数组,成员按传入顺序一一对应,成功的是 {status:'fulfilled', value:...},失败的是 {status:'rejected', reason:...}。
  • 三个方法返回的都是 promise 对象;"返回值立即拿到,但状态要等成员都改变才改变"——allSettled 会明显等 3 秒就是这个原因。
  • 易错点:arr 里写了字符串 'hello world',它不是 promise 也不会报错,会被 Promise.resolve('hello world') 自动转换成一个成功状态的成员,结果数组里就是 'hello world'。

示例 3:then 链式调用 —— 返回值规则、异常穿透、中断 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>then 链式调用</title>
</head>
<body>
  <script>
    // 一、then 的返回值是新的 promise,可以一直链下去
    Promise.resolve(100)
      .then(res => {
        console.log('第 1 层:', res);   // 100
        return 200;                      // 返回非 promise → 成功,结果就是返回值
      })
      .then(res => {
        console.log('第 2 层:', res);   // 200
        return 300;
      })
      .then(res => {
        console.log('第 3 层:', res);   // 300
        return 400;
      })
      .then(res => {
        console.log('第 4 层:', res);   // 400
        // 返回一个永远不改变状态的 promise → 链条在这里中断
        return new Promise(() => {});
      })
      .then(res => {
        console.log('第 5 层:不会执行');  // 卡住了,后面全部不执行
        return 500;
      })
      .catch(err => {
        console.log('catch 也不会执行:', err);
      });

    // 二、异常穿透:中间只写成功回调,错误会一路穿到最后的 catch
    Promise.resolve(1)
      .then(res => {
        console.log('穿透演示,第 1 层:', res);
        throw new Error('手动抛出的异常');  // 抛出异常 → 该 promise 变失败状态
      })
      .then(res => {
        console.log('不会执行');
      })
      .then(res => {
        console.log('也不会执行');
      })
      .catch(err => {
        console.log('catch 兜底:', err.message);
      });
  </script>
</body>
</html>

要点与易错点

  • then 的返回值还是 promise,它的状态和结果由回调函数的返回值决定:没有返回值 → 成功、结果是 undefined;返回非 promise 值 → 成功、结果就是这个值;返回一个 promise → 那个 promise 决定状态("中间商",原样传下去);抛出异常 → 失败、异常对象就是结果。
  • 异常穿透:链式调用中每层只写成功回调,中间某一层出错后,后面的成功回调都跳过,一路"穿透"到最后的 catch 才被处理。
  • 中断链条:某一层返回了一个永远不改状态的 promise(如 new Promise(() => {})),链条就卡死,后面的 then 和 catch 都不会执行——链式调用是严格按顺序的,中间一步卡住全都卡住。
  • 易错点:这里抛的是运行时异常(执行时才发现的错误),会变成失败状态交给 catch;如果是语法错误,在代码预处理阶段就挂了,整个脚本一行都跑不了,跟 Promise 没关系。

常见错误 ​

  1. 现象:new Promise 里写了 console.log,以为它会等异步任务结束才执行。→ 原因:执行器函数在实例化时同步执行。→ 修法:把需要等待的逻辑放进异步任务,并在完成时调用 resolve/reject。

  2. 现象:已经 resolve() 后又调用 reject(),期待状态还能改成失败。→ 原因:Promise 状态一旦改变不可逆。→ 修法:保证每条执行路径只调用一次状态变更函数,必要时提前 return。

  3. 现象:只创建 Promise 但不调用 resolve/reject,后面的 then/catch 一直不执行。→ 原因:状态一直 pending,回调不会触发。→ 修法:检查所有分支是否都能落到 resolve 或 reject,异步回调里也要确保执行。

  4. 现象:链式调用中后续 then 拿不到上一步结果。→ 原因:回调里没有 return,或返回了普通值却误以为还是原 Promise。→ 修法:需要传递结果就显式 return;需要继续异步就 return 一个 Promise。

  5. 现象:promise.then(...).catch(...) 中,前面的失败没有进入最近的 then 第二个参数,而是最后才被 catch 处理。→ 原因:只写了成功回调,拒绝沿链向后传递,形成异常穿透。→ 修法:明确在需要处理的位置写第二个回调,或统一在链尾 catch 并确认这是预期行为。

  6. 现象:Promise.all([p1, p2]) 结果顺序和完成顺序不一致,或某个失败后其余结果拿不到。→ 原因:all 结果按传入顺序排列;任一成员失败会立即整体失败。→ 修法:不要依赖完成顺序;需要全部结果无论成败时改用 allSettled,需要快速取先完成者用 race。

  7. 现象:把语法错误写进 Promise 执行器,期待被 catch 捕获。→ 原因:语法错误在代码解析阶段就报错,不会变成 Promise 的拒绝状态。→ 修法:区分语法错误与运行时异常;运行时异常可用 try/catch 或让 Promise 捕获,语法错误必须改代码。

  8. 现象:Promise.race 中以为一定取“最先成功”的结果。→ 原因:race 取的是最先完成者,成功或失败都算。→ 修法:若只想要成功结果,需要在成员内部处理失败,或改用其他组合逻辑。

练习 ​

  1. 写出下列代码的输出顺序,并解释执行器、then 回调、setTimeout 三者的先后关系:

    js
    console.log('A');
    new Promise((res) => &#123;
      console.log('B');
      res();
    &#125;).then(() => console.log('C'));
    setTimeout(() => console.log('D'));
    console.log('E');
  2. 构造一个 Promise 链:第一步返回普通值,第二步抛出异常,第三步只写成功回调,最后用 catch 处理。观察结果并说明异常穿透路径。

  3. 创建 4 个 Promise,其中第 2 个延迟最久但先传入,第 1 个最快完成。分别用 Promise.all 和 Promise.race 观察结果顺序与取值,并说明差异。

  4. 用 Promise.allSettled 处理“一个成功、一个失败、一个延迟成功”的三个 Promise,打印结果数组,并说明每个对象的 status、value/reason 对应关系。

  5. 写一个链式调用,在中间某一步故意不改变 Promise 状态,观察后续 then/catch 是否执行,并说明“中断链”发生在哪里。

原视频对照 ​

#视频时长
1回顾12:18
2Promsie静态方法all29:41
3Promsie静态方法all的应用-获取榜单歌曲列表21:20
4Promsie静态方法race09:07
5Promsie静态方法allSettled09:21
6Promise相关问题总结15:32

小结 ​

  1. Promise 状态只能从 pending 变为 resolved/rejected 一次,之后不可逆。
  2. 执行器函数同步执行,then/catch 注册的回调异步执行。
  3. then 返回新 Promise,其状态和结果由回调的返回值、返回的 Promise 或抛出的异常决定。
  4. catch 能统一处理链上的拒绝,但只写成功回调时会出现异常穿透。
  5. Promise.all 要求全部成功才成功,结果顺序按传入顺序,任一失败立即失败。
  6. Promise.race 取最先完成者,不区分成功或失败。
  7. Promise.allSettled 汇总所有成员结果,标准可迭代参数下整体为成功状态。
  8. 链式调用中必须保证每步状态能改变并正确 return,否则后续步骤会被卡住。