问题一
在系列(一)的开头,我曾经举过一个例子,但其中包含着错误(现已更正),现简化如下:
let p1 = new Promise((resolve, reject) => {
setTimeout(function() {
resolve(1);
}, 1000);
});
function p2(value) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2 + value);
}, 1000);
});
}
p1.then(res => {
console.log(res); // 1000ms后输出1,【这里是正确的】
}).then(p2).then(res => {
console.log(res); // 再过1000ms后输出3,【这里是错误的,输出NaN】
});
原因:
之所以会出现这种情况,是因为 promise 对象的每一个 then 其实是返回一个全新的 promise 对象,而当没有显式的指定返回的 promise
对象时,它会返回一个以 undefined 值 resolve 的 promise 对象,所以有如下代码:
let defaultP = p1.then(res => {
console.log(res); // 此处输出为1
// 此处返回默认的promise对象,它会立即以undefined值resolve
});
defaultP.then(res => {
console.log(res); // 此处输出为undefined
});
因此,p2接收到的 value 其实是 undefined,所以 2 + value 变成了NaN
使用Promise.resolve()
那么要想达到预期的结果,就要我们主动的返回一个 promise 对象,我们想让它以 p1 的 fulfilled 值来 resolve,这时使用 Promise 的 resolve 方法可以很简洁的实现:
let notDefaultP = p1.then(res => {
console.log(res); // 此处输出为1
return Promise.resolve(res); // 此处返回一个以res值resolve的promise对象
});
notDefaultP.then(res => {
console.log(res); // 此处输出为1
});
Promise.resolve不仅可以接受一个值作为参数,还可以接受
promise 对象或者 thenable 对象作为参数:
// 传入一个promise对象
let p = new Promise(resolve => {
resolve("I'm a promise!");
});
let p2 = Promise.resolve(p);
p2.then(res => {
console.log(res); // I'm a promise!
});
console.log(p2 === p); // true
// 传入一个thenable对象
let thenable = {
then: fulfilled => fulfilled("I'm thenable!")
};
let p3 = Promise.resolve(thenable);
p3.then(res => {
console.log(res); // I'm thenable!
});
详细请参考 MDN
问题二
let core = new Promise((resolve, reject) => {
reject(1);
});
let p = Promise.resolve({
then: (resolve, reject) => {
return core.then(resolve, reject).catch(err => {
console.log('1:', err); // 此处无输出
});
}
}).catch(err => {
console.log('2:', err); // 此处输出 2:1
});
这是我在研究“问题一”时无意在网上发现的另一个问题,其实并不难只是对初学者来说比较绕,所以拿来解析一下,其原理和“问题一”也很相似:
为什么第一个 catch 没有输出呢?很简单,因为 core.then(resolve, reject) 返回的是之前说的默认的 promise 对象,这个 promise 对象是以 undefined 值 resolve 的,因为没有 reject 所以无法被 catch。
因此要想达到预期效果有两种方式:
// 方式一,证明我们的理论
return core.then(resolve, reject).then(res => {
console.log('1:', res); // 此处会输出 1:undefined
});
// 方式二
return core.then(resolve, reason => {
reject(reason);
return Promise.reject(reason); // 主动返回一个以reason值reject的promise对象
}).catch(err => {
console.log('1:', err); // 此处会输出 1:1
});
而第二个 catch 之所以可以达到预期效果,是因为 Promise.resolve() 方法传入的 promise 或 thenable 对象 reject 之后,它返回的 promise 对象也会 reject,进而触发 catch:
let p = Promise.resolve({
then: (resolve, reject) => {
return core.then(resolve, reject)
// 【核心】,此处是将then对象的reject传入到core中,作为core reject的回调
// 所以当core reject的时候,then对象也会reject
.catch(err => {
console.log('1:', err);
});
}
}).catch(err => {
console.log('2:', err);
});
总结
当我们理解了Promise内部的实现原理,一切绕来绕去的怪异问题都是纸老虎 O(∩_∩)O~