Promise核心逻辑实现
示例
//index.js
let promise = new Promise((resolve,reject) => {
resolve('成功')//成功值
reject('失败')
})
promise.then(value => {
console.log(value)
}, reason => {
console.log(reason)
})
//newPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class NewPromise {
constructor(executor) {
executor(this.resolve,this.reject)
}
//promise状态
status = PENDING
value = undefined
reason = undefined
//值默认没有
resolve = value => {
//如果状态不是等待,阻止程序向下执行
if(this.status !== PENDING)return
this.status = FULFILLED
this.value = value
}
//使用箭头函数的原因:直接调用一个普通函数,函数里面的this指向是undefined的
reject = reason => {
if(this.status !== PENDING)return
//将状态更改为失败
this.status = REJECTED
this.reason = reason
}
//判断promise的状态,返回回调函数,需要传递value和reason
then(successCallback,failCallback){
//判断状态
if(this.status === FULFILLED){
successCallback(this.value)
}else if(this.status === REJECTED){
failCallback(this.reason)
}
}
}
module.exports = NewPromise
总结
-
Promise 就是一个类,在执行这个类的时候,需要传递一个执行器进去,执行器会立即执行
... constructor(executor){ executor(this.resolve,this.reject) } //构造函数接收执行 ... -
Promise 中有三种状态,分别为成功 fulfilled、失败 rejected、等待 pending
一旦状态确定就不可更改
graph LR
pending --> fulfilled
pending --> rejected
- resolve和reject函数是用来更改状态的
resolve: fulfilled
reject: rejected
-
then方法内部做的事情就判断状态,如果状态是成功,调用成功的回调函数,如果状态是失败。 调用失败回调函数 then方法是被定义在原型对象中的
then作用:判断promise的状态,返回回调函数,需要传递value和reason
-
then成功回调有一个参数value,表示成功之后的值,then失败回调有一个参数reason,表示失败后的原因
在Promise类中加入异步逻辑
示例,在执行器中加入异步代码
//index.js
let promise = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('成功')
},2000)
})
promise.then(value => {
console.log(value)
}, reason => {
console.log(reason)
})
//newPromise.js
class NewPromise {
...
successCallback = undefined
failCallback = undefined
//默认是undefined
...
resolve = value => {
//如果状态不是等待,阻止程序向下执行
if(this.status !== PENDING)return
this.status = FULFILLED
this.value = value
//判断成功回调是否存在,如果存在 调用
this.successCallback && this.successCallback(this.value)//在更改状态函数里执行成功/失败回调
}
//直接调用一个普通函数,函数里面的this指向是undefined的
reject = reason => {
if(this.status !== PENDING)return
//将状态更改为失败
this.status = REJECTED
this.reason = reason
//判断成功回调是否存在,如果存在 调用
this.failCallback && this.failCallback(this.reason)//在更改状态函数里执行成功/失败回调
}
then(successCallback,failCallback){
//判断状态
if(this.status === FULFILLED){
successCallback(this.value)
}else if(this.status === REJECTED){
failCallback(this.reason)
}else{
//等待,临时存储成功和失败回调
//将成功回调和失败回调存储起来
this.successCallback = successCallback
this.failCallback = failCallback
}
}
...
}
实现then方法多次调用添加多个处理函数
当有多个then时,会有多个成功和失败回调,此时应该将保存的回调函数变成一个数组,在状态更改时依次取出并且传递一个成功值/失败结果给成功回调/失败回调
//index.js
promise.then(value => {
console.log(value)
})
promise.then(value => {
console.log(value)
})
promise.then(value => {
console.log(value)
})
//将保存的回调函数变成一个数组
successCallback = []
failCallback = []
...
//this.successCallback && this.successCallback(this.value)
while(this.successCallback.length){
this.successCallback.shift()(this.value)
//shift()方法会移除并回传阵列的第一个元素
}
...
{
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
...
then方法的链式调用
- 当promise对象发生了链式调用时,应当在then方法里添加一个promise对象返回,以便于下一次then再次调用这个promise对象
//index.js
let promise = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('成功')
},2000)
})
promise.then(value => {
console.log(value)
return 100
//链式调用then方法
}).then(value => {
console.log(value)
//value = 100
})
//newPromise.js
then(successCallback, failCallback) {
let promise2 = new NewPromise((resolve,reject) => {
if (this.status === FULFILLED) {
let x = successCallback(this.value)
resolve(x)
//传递的时一个普通值x的时候,调用resolve()方法,把这个普通纸传递给下一个promise2对象
} else if (this.status === REJECTED) {
failCallback(this.reason)
} else {
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
})
return promise2
//调用了then方法会返回一个promise,以便于下一次then可以继续链式调用
}
-
当链式调用的上一个then return的值不是一个普通值而是一个promise对象时
-
判断 x 的值是普通值还是promise对象
-
如果是普通值,直接调用resolve
-
如果是promise对象,查看promsie对象返回的结果
-
再根据promise对象返回的结果,决定调用resolve 还是调用reject
//index.js let promise = new NewPromise((resolve,reject) => { resolve('成功') }) function other(){ return new NewPromise((resolve,reject) => { resolve('other') }) } promise.then(value => { console.log(value) return other()//other是一个promise对象 }).then(value => { console.log(value) //value = other })class NewPromise{ ... then(successCallback, failCallback) { let promise2 = new NewPromise((resolve,reject) => { if (this.status === FULFILLED) { let x = successCallback(this.value) resolvePromise(x,resolve,reject) //传递的时一个普通值x的时候,调用resolve()方法,把这个普通纸传递给下一个promise2对象,这里使用一个resolvePromise()方法去判断这个x是普通值还是promise对象 } else if (this.status === REJECTED) { failCallback(this.reason) } else { this.successCallback.push(successCallback) this.failCallback.push(failCallback) } }) return promise2 } ... } function resolvePromise(x,resolve,reject){ if(x instanceof NewPromise){ // x.then(value => resolve(value),reason => {reason})//查看状态 x.then(resolve,reject) }else{ resolve(x) } } -
then方法链式调用识别Promise对象自返回
当then返回了当前的promise对象时,需要识别是否是自对象。
解决:在resolvePromise中判断当前传值x是否为当前priomise对象
//index.js
let p1 = promise.then(value => {
console.log(value)
return p1
})
p1.then(value=>{
console.log(value)
},reason => {
console.log(reason)
})
//promise的循环调用
function resolvePromise(promise2, x,resolve,reject){
if(promise2 === x){
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if(x instanceof NewPromise){
// x.then(value => resolve(value),reason => {reason})//查看状态
x.then(resolve,reject)
}else{
resolve(x)
}
}
捕获/处理错误
//在执行器中进行错误捕获
class NewPromise{
constructor(executor) {
try{
executor(this.resolve, this.reject)
}catch(e){
this.reject(e)
}
}
...
}
注意,上一个then方法的错误在下一个then中捕获到
同理,不止要在执行器中进行错误捕获,在状态改变之后进行也要进行错误捕获
then(successCallback, failCallback) {
let promise2 = new NewPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) {
try {
failCallback(this.reason)
} catch (e) {
reject(e)
}
} else {
this.successCallback.push(()=>{
successCallback()
})
this.failCallback.push(() => {
failCallback()
})
//要对回调函数进行处理
}
})
return promise2
}
将then方法的参数变成可选参数
当then不传递任何参数时,最新一个then获取的value还是上一个最新then传递的参数
promise
.then()
.then()
.then(value => console.log(value))
//相当于
promise
.then(value => value)
.then(value => value)
//一层层向后进行传递相同的内容
.then(value => console.log(value))
//NewPromise.js
then(successCallback, failCallback){
successCallback = successCallback ? successCallback : value => value
failCallback = failCallback ? failCallback : reason => reason
}
Promise.all()
- 返回值是Promise对象
- 参数为数组,数组中可以传递普通值和promise对象
- 可以解决异步并发,允许按照异步API调用顺序得到异步API的执行结果
static all (array) {
let result = [];
let index = 0;
return new MyPromise((resolve, reject) => {
function addData (key, value) {
result[key] = value;
index++;
if (index === array.length) {
resolve(result);
}
}
for (let i = 0; i < array.length; i++) {
let current = array[i];
if (current instanceof MyPromise) {
// promise 对象
current.then(value => addData(i, value), reason => reject(reason))
}else {
// 普通值
addData(i, array[i]);
}
}
})
}
promise.resolve()
static resolve (value) {
if (value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value));
//普通值:创建promise对象,传递一个执行器,使用resolve方法将value进行返回
}
Promise.finally()
-
无论当前Promise对象的执行结果是成功还是失败,finally()方法当中的回调函数始终会被执行一次
-
在finally()方法的后面可以链式调用then方法来拿到Promise对象最终返回的结果
-
不是静态方法,要定义在原型对象身上
finally (callback) { return this.then(value => { return MyPromise.resolve(callback()).then(() => value); //需要借助resolve,不管是普通值还是promise对象,都使用resolve转化为promise对象 //再使用then地成功回调方法返回一个value //这样就可以等待callback()的返回值,再去执行return value //避免setTimeout没走完就返回了value }, reason => { return MyPromise.resolve(callback()).then(() => { throw reason }) }) } //index.js function p1 () { return new MyPromise(function (resolve, reject) { setTimeout(function () { resolve('p1') }, 2000) }) } function p2 () { return new MyPromise(function (resolve, reject) { // reject('失败') resolve('p2 finally'); }) } p2().finally(()=> { console.log('finally') return p1() }).then(value => { console.log(value) //没等两秒之后就已经输出了 },reason => { console.log(reason) })Promise.catch()
链式调用catch去处理reject()失败的情况
catch (failCallback) { return this.then(undefined, failCallback) //不传递成功回调,只传递失败回调 //return便于之后使用promise的其它方法 }