主题
Promise 概述与Promise 基本语法(Day17 1/3)
本页对应 Day17-Promise,共 6 段视频,约 1 小时 37 分。
学习目标
- 能准确说明
Promise.all的参数要求,并判断成员全部成功、存在失败、参数非可迭代对象时返回 Promise 的状态与结果。 - 能使用
Promise.all配合map并发请求榜单歌曲详情,并按传入顺序将歌曲名称与演唱者渲染到页面。 - 能对比说明
Promise.all、Promise.race、Promise.allSettled的返回值状态及结果规则,并针对给定场景选择正确方法。 - 能说明改变 Promise 状态的三种方式,并解释
then返回的新 Promise 状态由回调函数的返回值或抛出的异常决定。 - 能解释 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: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 没关系。
常见错误
现象:
new Promise里写了console.log,以为它会等异步任务结束才执行。→ 原因:执行器函数在实例化时同步执行。→ 修法:把需要等待的逻辑放进异步任务,并在完成时调用resolve/reject。现象:已经
resolve()后又调用reject(),期待状态还能改成失败。→ 原因:Promise 状态一旦改变不可逆。→ 修法:保证每条执行路径只调用一次状态变更函数,必要时提前return。现象:只创建 Promise 但不调用
resolve/reject,后面的then/catch一直不执行。→ 原因:状态一直pending,回调不会触发。→ 修法:检查所有分支是否都能落到resolve或reject,异步回调里也要确保执行。现象:链式调用中后续
then拿不到上一步结果。→ 原因:回调里没有return,或返回了普通值却误以为还是原 Promise。→ 修法:需要传递结果就显式return;需要继续异步就return一个 Promise。现象:
promise.then(...).catch(...)中,前面的失败没有进入最近的then第二个参数,而是最后才被catch处理。→ 原因:只写了成功回调,拒绝沿链向后传递,形成异常穿透。→ 修法:明确在需要处理的位置写第二个回调,或统一在链尾catch并确认这是预期行为。现象:
Promise.all([p1, p2])结果顺序和完成顺序不一致,或某个失败后其余结果拿不到。→ 原因:all结果按传入顺序排列;任一成员失败会立即整体失败。→ 修法:不要依赖完成顺序;需要全部结果无论成败时改用allSettled,需要快速取先完成者用race。现象:把语法错误写进 Promise 执行器,期待被
catch捕获。→ 原因:语法错误在代码解析阶段就报错,不会变成 Promise 的拒绝状态。→ 修法:区分语法错误与运行时异常;运行时异常可用try/catch或让 Promise 捕获,语法错误必须改代码。现象:
Promise.race中以为一定取“最先成功”的结果。→ 原因:race取的是最先完成者,成功或失败都算。→ 修法:若只想要成功结果,需要在成员内部处理失败,或改用其他组合逻辑。
练习
写出下列代码的输出顺序,并解释执行器、
then回调、setTimeout三者的先后关系:jsconsole.log('A'); new Promise((res) => { console.log('B'); res(); }).then(() => console.log('C')); setTimeout(() => console.log('D')); console.log('E');构造一个 Promise 链:第一步返回普通值,第二步抛出异常,第三步只写成功回调,最后用
catch处理。观察结果并说明异常穿透路径。创建 4 个 Promise,其中第 2 个延迟最久但先传入,第 1 个最快完成。分别用
Promise.all和Promise.race观察结果顺序与取值,并说明差异。用
Promise.allSettled处理“一个成功、一个失败、一个延迟成功”的三个 Promise,打印结果数组,并说明每个对象的status、value/reason对应关系。写一个链式调用,在中间某一步故意不改变 Promise 状态,观察后续
then/catch是否执行,并说明“中断链”发生在哪里。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 回顾 | 12:18 |
| 2 | Promsie静态方法all | 29:41 |
| 3 | Promsie静态方法all的应用-获取榜单歌曲列表 | 21:20 |
| 4 | Promsie静态方法race | 09:07 |
| 5 | Promsie静态方法allSettled | 09:21 |
| 6 | Promise相关问题总结 | 15:32 |
小结
- Promise 状态只能从
pending变为resolved/rejected一次,之后不可逆。 - 执行器函数同步执行,
then/catch注册的回调异步执行。 then返回新 Promise,其状态和结果由回调的返回值、返回的 Promise 或抛出的异常决定。catch能统一处理链上的拒绝,但只写成功回调时会出现异常穿透。Promise.all要求全部成功才成功,结果顺序按传入顺序,任一失败立即失败。Promise.race取最先完成者,不区分成功或失败。Promise.allSettled汇总所有成员结果,标准可迭代参数下整体为成功状态。- 链式调用中必须保证每步状态能改变并正确
return,否则后续步骤会被卡住。