同一Promise的catch方法为何被调用两次?不同链式写法的输出差异解析
同一Promise的catch方法为何被调用两次?不同链式写法的输出差异解析
别急,咱们一步步拆解这两个例子的核心区别,其实关键在于你调用.catch()的对象到底是不是同一个Promise,以及Promise的状态不可变性这两个关键点。
第一个例子:给同一个原始Promise绑定多个独立的catch回调
const promise = Promise.reject(); promise .catch(() => console.log(1)); promise .catch(() => console.log(2)); // Output: // 1 // 2
这里的核心逻辑是:你两次调用.catch(),都是直接绑定到同一个处于rejected状态的原始Promise上。
Promise有个核心特性:状态一旦确定(resolved/rejected)就永远不会改变。原始的promise已经是rejected状态了,不管你给它绑定多少个catch(或者then)回调,这些回调都会被依次触发——因为Promise会永久记住自己的最终状态,所有后续添加的回调都会基于这个状态执行。
所以第一个catch执行后,原始promise的rejected状态并没有任何变化,第二个catch作为独立绑定的回调,自然也会被调用,于是就输出了1和2。
第二个例子:链式调用的catch绑定的是全新Promise
const promise = Promise.reject(); promise .catch(() => console.log(1)) .catch(() => console.log(2)); // Output: // 1
这里的逻辑完全不同,因为**.catch()方法本身会返回一个全新的Promise**。我们拆解下具体执行流程:
- 原始
promise是rejected状态,触发第一个.catch()回调,执行console.log(1)。 - 这个第一个
.catch()的回调函数没有返回rejected的Promise,也没有抛出错误,所以它会默认返回一个处于resolved状态的新Promise。 - 后面的第二个
.catch(),其实是绑定在这个新的resolved Promise上的——而resolved状态的Promise不会触发catch回调,所以第二个catch根本不会执行,最终只输出1。
你之前的误解在于以为第一个catch会改变原始Promise的状态,但实际上Promise的状态是不可变的,链式调用里的catch操作的是新生成的Promise,而非原始的那个。
备注:内容来源于stack exchange,提问作者Pavel Orlov




