关于Promise当中的一些特性,咱们需求了解并且掌握,今天咱们来依据特性一步一步的完成咱们的Promise源码,更好的了解并且掌握它

1、resolve reject 完成

//html
let p = new Promise((resolve, reject) => {
    resolve('OK11');  
    resolve('OK');  
    //reject('rrr')
});
console.log(p)
//js
class Promise{
    constructor(executor){
        let _this = this
        _this.PromiseState = 'pending' //用于保存状况
        _this.PromiseResult = null //用于保存成果
        let resolve = function(data){
            _this.PromiseState = 'success'//没有使用箭头函数,this指向要改动
            _this.PromiseResult = data
        }
        let reject = function(data){
            _this.PromiseState = 'rejected'
            _this.PromiseResult = data
        }
        executor(resolve,reject)
    }

一开始关于executor(resolve,reject)这一段不太了解,可以了解为new Promise实例化的时分传入一个函数,放到construtor中进行履行,函数需求传入俩个参数,需求用resolve和reject两个函数作为参数,这里在传入的函数中调用resolve即调用constructor中的resolve

来看下控制台打印成果

带着问题寻找答案,实现源码也许会更加轻松

2、只能改动一次状况

Promise中只能改动一次状况,所以每次改动状况前判别一下状况是否现已改动了,这个比较简单

//html
let p = new Promise((resolve, reject) => {
    resolve('OK11');  
    resolve('OK');  
});
//js
let resolve = function(data){
+    if(_this.PromiseState!='pending') return
     ...
}
let reject = function(data){
+    if(_this.PromiseState!='pending') return
     ...
}

现在只会履行一次resolve

带着问题寻找答案,实现源码也许会更加轻松

3、抛出过错改动

Promise中假如没有改动状况而是抛出过错,需求将状况改动为reject,那么咱们在executor履行的时分捕获一下过错,假如有过错,改动状况

let p = new Promise((resolve, reject) => {
-    resolve('OK11');  
-    resolve('OK');  
+    throw 'error'
});
class Promise{
    constructor(executor){
+        try {
            executor(resolve,reject)
+        } catch (error) {
+            reject(error)
+        }
+    }

带着问题寻找答案,实现源码也许会更加轻松

4、then完成

当进入到then的时分 promise同步状况下 履行到then的时分状况是现已改动的,then中传入两个函数,咱们依据状况的不同调用不同的函数,调用函数的时分有一个value值,

这个value是履行resolve('OK')的时分现已将ok保存到PromiseResult中,所以在then中输出value的时分,其实便是输出PromiseResult

//html
let p = new Promise((resolve, reject) => {
    resolve('OK');  
});
p.then(value => {
    console.log(value)
}, reason=>{
    console.warn(reason)
})
//js
+ then(onResolved,onRejected){
+   if(this.PromiseState=='success'){
+        onResolved(this.PromiseResult)
+    }
+    if(this.PromiseState=='rejected'){
+        onRejected(this.PromiseResult)
+    }
}

此刻咱们的OK现已打印出来

带着问题寻找答案,实现源码也许会更加轻松

5.异步调用时分then中的问题

以下这段代码不会输出ok,因为在then履行的时分,由于事件循环,then调用的时分resolve还未调用,所以在then中PromiseState的状况依然未pending,因而不会输出,所以咱们需求加一个判别

let p = new Promise((resolve, reject) => {
    setTimeout(()=>{
        resolve('OK');  
    },100)
});
p.then(value => {
    console.log(value)
}, reason=>{
    console.warn(reason)
})
p.then(value => {
    console.log(2222)
}, reason=>{
    console.warn(reason)
})

关于then履行的时分状况仍未pending的状况,咱们将回调存到回调列表中,等待resolve调用的时分再去履行一切回调,之所以用数组保存,因为可能有多个then回调

constructor(executor){
+    _this.callbacks = []
    let resolve = function(data){
+        _this.callbacks.forEach((item)=>{
+            item.onResolve(_this.PromiseResult)
+        })
    }
    let reject = function(data){
+        _this.callbacks.forEach((item)=>{
+            item.onReject(_this.PromiseResult)
+        })
    }
then(onResolve,onReject){
+    if(this.PromiseState=='pending'){//处理resolved异步比then慢履行的时分
+        this.callbacks.push({onResolve,onReject})
+    } 
} 

带着问题寻找答案,实现源码也许会更加轻松

完成promise的回来值

假如回来值是一个非promise目标,回来状况设置为成功, 假如回来值是一个异常,回来状况设置为失利

咱们知道then中回来的也是一个Promise,所以咱们给then中回来一个Promise,只需求在promise中做两件工作,履行回调,改动状况

假如回来值是一个promise,此刻咱们的promise现已有then办法了,咱们直接用then办法来处理状况的改动即可,最后加上一层try的过错检验,reject的办法相同

let p = new Promise((resolve, reject) => {
    resolve(1);  
});
let res = p.then(value => {
    return new Promise((resolve,reject)=>{
        resolve(2)
    })
}, reason=>{
    console.warn(reason)
})
console.log(p)
console.log(res)
//js
    then(onResolve,onReject){
        if(this.PromiseState=='pending'){
            this.callbacks.push({onResolve,onReject})
        } 
        return new Promise((resolve,reject)=>{
            if(this.PromiseState=='success'){
                 try {
                    let res = onResolve(this.PromiseResult)//履行回调
                    if(res instanceof Promise){
                        res.then((v)=>{//之所以加这一层 是因为promise状况改动了 可是里边的值没输出 所以要加个then,不然就成了promise里边包裹着一个pormise
                            resolve(v)//改动状况
                        },(r)=>{
                            reject(r)//改动状况
                        })
                    }else{
                        resolve(res)//改动状况
                    }
                 } catch (error) {
                     reject(error)
                 }  
            }
        })
    }

履行一下看看

let p = new Promise((resolve, reject) => {
    resolve(1);  
});
let res = p.then(value => {
    return new Promise((resolve,reject)=>{
        resolve(2)
    })
}, reason=>{
    console.warn(reason)
})
console.log(p)
console.log(res)

假如没有判别res instanceof Promise ,第二个then的会输出一个promise

带着问题寻找答案,实现源码也许会更加轻松

加上判别后的成果

带着问题寻找答案,实现源码也许会更加轻松

一开始我在判别回来值为promise这个地方一向搞不懂,为啥要履行then,为啥调用resolve,所以在写源码的时分应该多着手打印、debugger输出,下面是我对这段代码的解说

return new Promise((resolve,reject)=>{
...
if (result instanceof Promise) {//假如是 Promise 类型的目标
    result.then(v => {
        //之所以加这一层 是认为result是一个promise,
        // 他的成功和失利决议了外层promise的状况(也便是真正then回来的promise)
        //那么他成功 则调用外层的成功
        resolve(v);
    }, r => {
        reject(r);
    })
}

本文正在参与「金石计划 . 分割6万现金大奖」