then 方法返回值与状态传递详解文章目录then 方法返回值与状态传递详解前言一、then 方法基础认知与返回值规则1.1 基础认知then 返回新 Promise1.2 核心规则新 Promise 状态的决定因素1.2.1 原则 1回调返回非 Promise/非thenable 值 → 新 Promise 为 fulfilled 状态值为返回值一、原 Promise 为成功resolve的场景二、原 Promise 为失败reject的场景1.2.2 原则 2回调返回 Promise 实例或 thenable 对象 → 新 Promise 状态与之一致一、原 Promise 为成功resolve的场景二、原 Promise 为失败reject的场景1.2.3 原则 3回调函数有异常 → 新 Promise 状态为失败1.3 补充then 返回的永远是新 Promise1.4 补充then 允许被多次调用总结前言在前端异步编程中Promise 已经成为处理异步逻辑的标配。很多同学会用 then 写链式调用但对其底层机制并不清楚then执行后返回的到底是什么新 Promise 的状态由什么决定回调的返回值又会如何影响整个流程本文就从最核心的点入手通过大量实例一步步讲清楚then方法返回新 Promise 的规则、状态传递逻辑以及常见的细节问题帮你真正吃透 Promise。一、then 方法基础认知与返回值规则then是 Promise 原型上的方法它永远返回一个新的 Promise 实例这个新实例的状态和值由 then 中执行的回调函数决定。我们要先明白两件事1-then方法是Promise实例原型上的方法2-then方法返回的值是一个Promise实例。constpnewPromise((resolve,reject){});constp1p.then(function(){},function(){});console.log(p1);// 得到的是一个 Promise 实例状态是 pending值是 undefined目前 p 的状态为pending值为 undefined。在 p 的原型上有个then方法接收两个回调函数要执行成功的回调还是失败的回调取决于 p 的状态p 的状态为成功就执行成功的回调p 的状态为失败就执行失败的回调p 的状态没有发生改变谁都不执行。1.1 基础认知then 返回新 Promisethen方法的核心特性之一是无论回调如何执行它永远返回一个全新的 Promise 实例与原 Promise 实例完全独立。我们可以通过以下代码验证这一点// 1. 创建一个原始 PromiseconstpnewPromise((resolve)resolve(100));// 2. 调用 then把返回值存起来这个就是 then 新建的 Promiseconstp2p.then((){});// 3. 直接对比是不是同一个对象console.log(pp2);// 输出false})注意then指定的成功回调与失败回调是异步执行的会被放入微任务队列等待当前同步代码执行完成后才会运行。以下代码最终会先输出1-over再输出2-成功回调 1constpnewPromise((resolve,reject){resolve(1);});p.then(value{console.log(2-成功回调,value);},reason{console.log(失败回调,reason);})console.log(1-over);1.2 核心规则新 Promise 状态的决定因素constpnewPromise((resolve,reject){// 这里没有调用 resolve/reject → p 永远是 pending 状态});constp1p.then(function(){},function(){});console.log(p1);// 得到的是一个 Promise 实例状态是 pending值是 undefinedp1 的状态由谁来决定p1 是一个 Promise 实例实例的状态和值由p.then执行的成功或失败的回调函数决定p 的状态为成功 → 成功回调决定 p1 的状态和值p 的状态为失败 → 失败回调决定 p1 的状态和值基于这个核心逻辑我们可以总结出3 条明确的规则来精准判断新 Promise 的最终状态和值1.2.1 原则 1回调返回非 Promise/非thenable 值 → 新 Promise 为 fulfilled 状态值为返回值then函数返回的永远都是一个新的Promise实例例如p1如果执行的回调函数返回的是一个非 Promise 且非 thenable 的值那么 p1 的状态就为成功fulfilled值为返回值。这里的「非 Promise / 非 thenable 值」包含 undefined、字符串、数字、普通对象等。一、原 Promise 为成功resolve的场景无论回调有没有返回值只要返回的是非 Promise / 非 thenable 值新 Promise 一定是fulfilled。1.无返回值隐式返回 undefinedconstpnewPromise((resolve,reject){resolve(1);});constp1p.then(value{// 这里 p 的状态为成功所以看成功的回调看的就是返回值// 这里成功的回调没有返回值所以会隐式返回一个 undefinedundefined是非Promise/非thenable值console.log(成功回调,value);},reason{console.log(失败回调,reason);});console.log(p1);// 状态是成功 fulfilled值是 undefined2.有返回值返回普通值constpnewPromise((resolve,reject){resolve(1);});constp1p.then(value{console.log(成功回调,value);// 这里p的状态为成功所以就看成功的回调看的就是返回值。return100;// 返回 100非 Promise/非 thenable},reason{console.log(失败回调,reason);});console.log(p1);// 状态是成功 fulfilled值是 100二、原 Promise 为失败reject的场景⚠️重点即使原 Promise 失败只要执行的失败回调返回了非 Promise / 非 thenable 值新 Promise 依然会变为fulfilled实现「错误被回调消化」。1.无返回值隐式返回 undefinedconstpnewPromise((resolve,reject){reject(1);});constp1p.then(value{console.log(成功回调,value);return100;},reason{// 这里 p 的状态为失败所以看失败的回调看的就是返回值// 这里失败的回调没有返回值所以会隐式返回一个 undefinedundefined 是非 Promise / 非 thenable 值console.log(失败回调,reason);});console.log(p1);// 状态是成功 fulfilled值是 undefined2. 有返回值返回普通值constpnewPromise((resolve,reject){reject(1);});constp1p.then(value{console.log(成功回调,value);return100;},reason{console.log(失败回调,reason);return200;});console.log(p1);// 状态是成功 fulfilled值是 200核心总结p1 的状态只取决于当前执行的回调p 成功 → 看成功回调的返回值p 失败 → 看失败回调的返回值只要返回的是非 Promise / 非 thenable 值无论原 Promise 是成功还是失败p1 都会变为fulfilled值为返回值。1.2.2 原则 2回调返回 Promise 实例或 thenable 对象 → 新 Promise 状态与之一致then函数返回的永远都是一个新的Promise实例如果执行的成功或失败的回调函数返回的是一个 Promise 实例或 thenable 对象那么得到的p1的状态以及值与回调函数返回的Promise/thenable状态和值相同。一、原 Promise 为成功resolve的场景执行成功回调p1 的状态完全追随回调返回的Promise/thenable的状态。情况 1返回的Promise/thenable状态为pending执行的成功回调函数返回的是一个Promise 实例或 thenable 对象状态为pending值为 undefined。constpnewPromise((resolve,reject){resolve(1);});constp1p.then(value{console.log(成功回调,value);returnnewPromise((){});// 这里返回的 Promise 的状态为 pending值为 undefined},reason{console.log(失败回调,reason);return200;});console.log(p1);// 状态是 pending值是 undefined情况 2返回的Promise/thenable状态为fulfilled执行的成功回调函数返回的是一个Promise 实例或 thenable 对象且实例的状态为fulfilled值为 200。constpnewPromise((resolve,reject){resolve(1);});constp1p.then(value{console.log(成功回调,value);returnnewPromise((resolve,reject){resolve(200);// 这里返回的 Promise 的状态为成功 fulfilled值为 200// 同理如果这里是 reject(200)那么 p1 的状态和值就是 rejected值为 200});},reason{console.log(失败回调,reason);return200;});console.log(p1);// 状态是 fulfilled值是 200二、原 Promise 为失败reject的场景执行失败回调p1 的状态同样完全追随回调返回的Promise/thenable的状态重点原 Promise 失败新 Promise 仍可成功。情况 3返回的Promise/thenable状态为pending执行的失败回调函数返回的是一个 Promise 实例或 thenable 对象状态为pending值为 undefined。constpnewPromise((resolve,reject){reject(1);});constp1p.then(null,reason{console.log(失败回调,reason);returnnewPromise((){});// 返回 pending 状态的 Promise});console.log(p1);// 状态 pending值 undefined情况 4返回的Promise/thenable状态为fulfilled执行的失败回调函数返回的是一个Promise 实例或 thenable 对象且实例的状态为fulfilled值为 9。constpnewPromise((resolve,reject){reject(1);});constp1p.then(value{},reason{console.log(失败回调,reason);returnnewPromise((resolve,reject){// 是空这里返回的 Promise 的状态就为 pending值是 undefinedresolve(9);// 这里返回的 Promise 的状态为成功 fulfilled值为 9// 同理如果这里是 reject(9)那么 p1 的状态和值就是 rejected值为 9});});console.log(p1);核心总结p1 的状态只取决于当前执行的回调p 成功 → 看成功回调返回的Promise/thenablep 失败 → 看失败回调返回的Promise/thenable无论原 Promise 是成功还是失败p1 都会 1:1 追随回调返回对象的状态和值。返回值要么是Promise/thenable要么是非 Promise / 非 thenable。这里其实已经涵盖了大部分的情况了还有一种特殊的情况1.2.3 原则 3回调函数有异常 → 新 Promise 状态为失败如果回调函数执行过程中抛出异常throw那么新 Promise p1 的状态会直接变为失败rejected值为抛出的异常信息。constpnewPromise((resolve,reject){reject(1);});constp1p.then(value{console.log(成功回调,value);returnnewPromise((resolve,reject){reject(200);});},reason{console.log(失败回调,reason);throw异常;// 抛出异常后后续代码不会执行// 以下代码为不可达代码抛出异常后直接失效// return new Promise((resolve, reject) {// reject(9);// });});console.log(p1);核心说明只要回调函数执行过程中抛出异常throw无论后续原本要返回什么值p1 都会直接变为失败rejected值为异常信息。这是一个「中断型」规则一旦抛出异常回调内后续的所有代码包括 return 语句会立即失效p1 的状态被强制锁定为rejected与原 Promise p 是成功还是失败无关。原 Promise 为成功resolve执行成功回调若回调抛出异常p1 变为rejected原 Promise 为失败reject执行失败回调若回调抛出异常p1 变为rejected三条核心规则总览原则 1回调返回非 Promise / 非 thenable 值→ 新 Promise 为fulfilled状态值为返回值原则 2回调返回Promise 实例或 thenable 对象→ 新 Promise 状态与返回值完全一致原则 3回调执行过程中抛出异常→ 新 Promise 直接变为rejected状态值为异常信息1.3 补充then 返回的永远是新 Promisethen方法返回的永远是一个全新的 Promise 实例例如 p1无论回调函数返回什么内容。以下通过三个场景逐一验证。场景 1回调返回普通值演示异步性核心验证then的回调函数是异步执行的且返回普通值非 Promise/thenable时p1 最终状态为fulfilled。constpnewPromise(resolve{// 只用到了resolve所以reject就可以不写resolve(100);// p的状态为成功值为100执行成功回调});constp1p.then(value{return1;// 回调返回普通值});console.log(p1);// 同步输出时是 Promise {pending}异步后变为 fulfilled值为 1// 这里输出的就是fulfilled,值为1 但是控制台展示的是Promis{pending}为什么会看到pending因为 JavaScript 引擎会先执行同步代码console.log(p1)此时回调函数还未被加入微任务队列所以 p1 的状态是pending。当同步代码执行完毕、栈为空时事件循环才会处理微任务执行回调函数此时 p1 的状态才会更新为fulfilled值为 1。场景 3回调返回 Promise验证 “状态追随”核心验证根据 原则 2当回调返回 Promise 实例 /thenable 对象时p1 的状态会完全追随该 Promise 的状态。constpnewPromise(resolve{resolve(100);// p 状态为成功});constp1p.then(value{// 走成功回调返回一个失败的新 PromisereturnnewPromise((resolve,reject){reject(200);});});console.log(p1);// 初始状态为 pending异步处理后变为 rejected值为 200核心解释console.log(p1)是同步代码会立刻执行。此时 then 的回调还未运行所以同步输出时 p1 一定是Promise {pending}。只有等同步代码执行完毕微任务队列处理后p1 才会追随回调返回的 Promise状态更新为rejected值为 200。场景 3回调返回 Promise验证 “新实例”核心验证虽然 p1 的状态和值与回调返回的 Promise 完全一致但它绝不是同一个对象。// 1. 先创建一个已失败的 Promise 实例 p2constp2newPromise((resolve,reject){reject(200);});// 2. 让 p1 返回 p2constpnewPromise(resolveresolve(100));constp1p.then(value{returnp2;// p1 会“追随” p2 的状态});// 3. 关键验证p1 和 p2 不相等console.log(p1p2);// false结论p1 的状态虽然与 p2 保持一致但它本质上是一个全新的引用。then方法每次调用都会创建并返回一个独立的 Promise 实例这就是「then 返回的永远是新 Promise」的铁证。1.4 补充then 允许被多次调用同一个 Promise 实例可以多次独立调用then每个then都会独立监听 Promise 的状态变化互不干扰、各自返回全新的 Promise 实例constpnewPromise((resolve,reject){resolve(200);});p.then(value{console.log(then1:,value);});p.then(value{console.log(then2:,value);});p.then(value{console.log(then3:,value);});执行结果then1: 200 then2: 200 then3: 200核心说明3 个then会按注册顺序依次执行各自独立拿到 Promise 的最终值每个then都会返回一个全新的 Promise 实例互相独立不会互相阻塞即使在 Promise 已经resolve/reject后再调用then回调也会立即执行保证异步逻辑的一致性总结本文我们详细梳理了 Promise 中then方法的核心行为可以归纳为以下几点then是 Promise 原型上的方法它永远返回一个新的 Promise 实例而不是原 Promise。新 Promise 的状态和结果由then中实际执行的回调函数决定原 Promise 成功则看成功回调失败则看失败回调。若回调返回非 Promise 类型值新 Promise 状态为成功结果为该返回值。若回调返回Promise 实例新 Promise 会完全 “跟随” 该 Promise 的状态和结果。若回调内部抛出异常新 Promise 状态直接变为失败结果为异常信息。同一个 Promise 可以多次调用then多个回调独立执行、互不影响。理解这些规则是写出可靠的 Promise链式调用、掌握async/await语法糖底层逻辑的关键。