文章目录
书接上回,上一篇手写promise原理系列一:promise基础知识解析,then、catch、resolve、reject、all、race等promise api的用法中讲解了一些promise的基础知识以及常用API的使用,这篇文章的重点在于深入了解promise的运行方式,梳理其中的关键性逻辑,为接下来正式手写promise做一些准备工作。
大家千万不要着急,当真正进入手写promise环节后,可能还需要不断返回当前篇章,仔细斟酌这其中字句,才能真正了解promise中的无穷奥妙,全是高阶函数以及你不知道的JavaScript 。
一、如何改变promise的状态?
改变promise状态有三种情况,如下:
- resolve() --> 成功 fulfilled
- reject() --> 失败 rejected
- throw --> 失败 rejected
throw 抛出异常示例:
let p = new Promise((resolve, reject) => {
throw "error"; // 抛出一个字符串错误,内容为'error'
})
p.catch((reason) => { console.log(reason); })
console.log(p);
二、一个promise指定多个成功或失败回调,都会调用么?
成功回调示例:
let p = new Promise((resolve, reject) => {
resolve("OK")
})
// 指定回调1
p.then(value => {
console.log(value);
console.log("111");
})
// 指定回调2
p.then(value => {
console.log(value);
console.log("222");
})
由上图可知then中指定的多个成功回调函数全部执行了。
失败回调示例:
let p = new Promise((resolve, reject) => {
reject("NO")
})
// 指定回调1
p.then(value => {
console.log(value);
}, reason => {
console.log(reason);
console.log("111");
})
// 指定回调2
p.then(value => {
console.log(value);
}, reason => {
console.log(reason);
console.log("222");
})
由上图可知then中指定的多个失败回调函数全部执行了。
三、改变promise状态和then中的回调函数谁先执行谁后执行?
这里我之前看的时候有点蒙,后来整理了一下思路,先说结论:不管是同步改变状态,还是异步改变状态,永远是先改变状态,再执行then中的回调函数。
这个问题有两种情况需要说明,以 resolve() 为例:
- 同步执行改变状态,就是先执行resolve(),然后执行then中回调函数。
let p = new Promise((resolve, reject) => {
resolve("OK");
})
p.then(value => {
console.log(value);
})
按照代码执行顺序,从上往下执行,先执行 resolve("OK")
,然后执行 p.then()
,因为没有其他同步代码,所以直接执行 then 中的回调函数,输出 value 值为 "OK"
。
- 异步执行改变状态,先执行 p.then() ,等待状态发生改变后,再回头执行then中的回调函数。
let p = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve("OK");
}, 1000)
})
p.then(value => {
console.log(value);
})
上面使用了 setTimeout()
宏任务,延迟1s后改变状态。按照代码执行顺序,此时 p.then() 已经执行,但是因为状态还未改变,所以 p.then() 中的回调函数被缓存起来(then方法内部做了缓存处理),等待状态改变后再执行。此时1s过后,控制台输出 value 的值为 "OK"
。
四、promise.then() 返回的 promise 对象的结果由什么决定?
先明确一点,函数中若无 return 语句,则函数的默认返回值为 undefined 。这个想必大家应该都清楚!
接下来说明 then 返回的 promise 对象的结果由什么决定?
- 如果抛出异常,则 then 返回的 promise 对象结果为 rejected 失败。
let p = new Promise((resolve, reject) => {
resolve("OK")
})
let result = p.then(value => {
throw "error"; // 抛出异常
})
result.catch(reason => {
console.log(reason); // "error"
})
console.log(result); // result为then返回的promise对象
- 如果返回的是非 promise 类型的任意值,promise对象的结果为 fulfilled 成功。
let p = new Promise((resolve, reject) => {
resolve("OK")
})
let result1 = p.then(value => {
console.log(value);
})
let result2 = p.then(value => {
return "111";
})
console.log(result1);
console.log(result2);
- 如果返回的是一个 promise 对象,则此 promise 对象的结果就是 then 返回的 promise 对象的结果。
let p = new Promise((resolve, reject) => {
resolve("OK")
})
let result1 = p.then(value => {
return new Promise((resolve, reject)=>{
resolve("成功啦")
})
})
let result2 = p.then(value => {
return new Promise((resolve, reject)=>{
reject("失败啦")
})
})
console.log(result1);
console.log(result2);
五、promise如何进行链式调用?
因为 promis e的 then 方法返回的是一个新的 promise 对象,所以可以再一次调用 then 方法,形成链式调用。本质就是套娃!
let p = new Promise((resolve, reject) => {
resolve("OK")
})
let result = p.then(value => {
console.log(value); // OK
}).then(value => {
console.log(value); // undefined
return "111";
}).then(value => {
return null;
})
console.log(result); // 成功的promise对象,结果值为null
六、如何中断promise链式调用?
方法:返回一个 pending 状态的 promise 对象。
let p = new Promise((resolve, reject) => {
resolve("OK")
})
let result = p.then(value => {
console.log(value); // "OK"
return new Promise(() => {}); // 返回一个未改变状态的promise对象,中断then链式调用
}).then(value => {
console.log(value); // 无法打印
return "222"
}).then(value => {
console.log(value); // 无法打印
return "333"
})
console.log(result); // result是一个pending状态的promise对象
七、promise异常穿透(promise.catch())
promise 异常穿透,就是在使用 promise.then() 方法时,在链式调用最后面指定失败的回调 promise.catch() 。前面任何操作出现了异常,都会被传递到最后失败的回调处理中。
promise.catch() 方法的返回值为一个新的 promise 对象,返回结果与上面 promise.then() 的返回结果描述一致。
let p = new Promise((resolve, reject) => {
resolve("OK")
})
let result = p.then(value => {
console.log(value); // "OK"
throw "ERROR"; // 抛出异常
}).then(value => {
console.log(value); // 不会打印
return "111";
}).then(value => {
console.log(value); // 不会打印
return null;
}).catch(reason => {
console.log(reason); // "ERROR"
})
console.log(result); // result是调用catch方法返回的新promise对象