promise源码库

先直接上源码吧。

if(!window.Promise) {
    function Promise(fn) {
        var self=this;
        this.status = 'pending';
        this.thenCache = [];
        this.count = 0
        if(!(this instanceof Promise)) {
            throw 'Defer is a constructor and should be called width "new" keyword';
        }
        if(typeof fn !== 'function') {
            throw 'Defer params must be a function';
        }
        //为了让传进来的函数在then后实行
        setTimeout(function() {
            try {
                fn.call(this, self.resolve.bind(self), self.reject.bind(self))
            } catch(e) {
                self.reject(e);
            }
        }, 0);
    }
    Promise.prototype.resolve = function(value) {
        this.value = value;
        this.status = 'resolved';
        this.triggerThen();
    }
    Promise.prototype.reject = function(reason) {
        this.value = reason;
        this.status = 'rejected';
        this.triggerThen();
    }
    Promise.prototype.then = function(onResolve, onReject) {
        this.thenCache.push({ onResolve: onResolve, onReject: onReject });
        console.log('this', this)
        return this;
    }
    Promise.prototype.catch = function(fn) {
        if(typeof fn === 'function') {
            this.errorHandle = fn;
        }
    };
    Promise.prototype.triggerThen = function() {
        console.log('this.thenCache', this.thenCache)
        console.log('this.status', this.status)
        var current = this.thenCache.shift(),
            res;
        console.log('current', current)
        if(!current && this.status === 'resolved') {
            // console.log('--11--', + new Date())
            return this;
        } else if(!current && this.status === 'rejected') {
            if(this.errorHandle) {
                this.value = this.errorHandle.call(undefined, this.value);
                this.status = 'resolved';
                console.log('--11--', + new Date())
            }
            return this;
        };
        if(this.status === 'resolved') {
            // console.log('--222--', + new Date())
            res = current.onResolve;
        } else if(this.status === 'rejected') {
            console.log('--222--', + new Date())
            res = current.onReject;
        }
        this.count ++;
        if(typeof res === "function") {
            try {
                this.value = res.call(undefined, this.value);
                this.status = 'resolved';
                console.log('-ddd--', + new Date())
                this.triggerThen();
                // console.log('this.count', this.count, + new Date())
            } catch(e) {
                this.status = 'rejected';
                this.value = e;
                return this.triggerThen();
            }
        } else {
            console.log('--44--')
            this.triggerThen();
        }
    }
    window.Promise = Promise;
}

之前写过怎样组织一个promise库,参考的美团点评的网站,写到背面发明Promise.resolve()直接挪用就会涌现问题。报错上面的库,也是援用Talking Coder的一篇博客,逐步最先明白promise内部是怎样完成的了,固然照样有一些疑问。比方上面的库,须要解释window.Promise = Promise和if(!window.Promise) {} 内部的代码在debug的时刻才看得见。但假如解释掉,直接Promise.resolve()又回一样报resolve不是一个要领。

阮一峰在promise基本篇提到过,阮一峰promise基本引见,then返回的是一个新的Promise实例,不是本来的谁人实例。这里提到的本来的谁人实例,我想应该是第一次实例化的Promise实例对象。这里有点不懂,为什么then函数在return this后,就会返回一个新的Promise实例对象。

也许讲解下此Promise库的道理吧。

setTimeout(function() {
            try {
                fn.call(this, self.resolve.bind(self), self.reject.bind(self))
            } catch(e) {
                self.reject(e);
            }
}, 0);

call 和 bind 都是为了绑定this的指向,由于直接回调,this在浏览器内里指向的是window对象,绑定fn实行的时刻this指向Promise的实例对象。同理绑定resolve和reject的this指向。
setTimout 0秒后,是为了让fn在行列的末了实行。这里的行列一会再理会。或者说让resolve或reject在行列的末了实行。
假如去掉setTimeout 0秒后,那末在实例化Promise的时刻,就会马上实行回调fn,进而实行resolve或reject函数,而此时then还未来得及push须要thenAble的回调行列,致使再实行resolve或reject内里的triggerThen()要领时,没法实行(此时回调行列为空。)

Promise.prototype.then = function(onResolve, onReject) {
    this.thenCache.push({ onResolve: onResolve, onReject: onReject });
    return this;
}

then 现实是一个回调行列,当有3个then,那末回调行列就会有三个。然后通this.triggerThen()
以此递归挪用,直接回调行列被挪用终了后,再实行fn中的resolve或reject函数。

再剖析下状况和返回值
在triggerThen函数里有这么几行代码

if(typeof res === "function") {
        try {
                this.value = res.call(undefined, this.value);
                this.status = 'resolved';
                this.triggerThen();
        } catch(e) {
                this.status = 'rejected';
                this.value = e;
                return this.triggerThen();
        }
        } else {
            this.triggerThen();
        }

能够看出,当js无语法报错的时刻,实行的try代码。此时将then()中第一个回调函数实行的value赋值给了this.value。在new Promise()的回调函数中,假如实行过resolve()的话,那末此时赋值就是第二次赋值了。同理this.status。当涌现语法报错的时刻,会实行catch,此时将毛病参数e一样赋值给this.value。状况也被变成rejected。同理假如在new Promise()回调中实行过reject,那末此时赋值也是第二次赋值了。这就考证了阮一峰在Promise基本引见将的下面的代码逻辑。

const promise = new Promise(function(resolve, reject) {
  throw new Error('test');
});
promise.catch(function(error) {
  console.log(error);
});
// Error: test

catch 跟then的第二个参数是一个逻辑。而且then的第二个参数现实我们很少回调。都写catch来非常捕捉的。

实在写这篇文章的时刻,对Promise照样相识在表面上,但收成依旧照样有的,准建明白了Promise是怎样完成的,比方resolve和then回调的关联,

    原文作者:健儿
    原文地址: https://segmentfault.com/a/1190000013492533
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞