Promise原理與實(shí)現(xiàn)

Promise標(biāo)準(zhǔn)

  1. Promise 規(guī)范有很多,如Promise/A捻勉,Promise/B册舞,Promise/D 以及 Promise/A 的升級(jí)版 Promise/A+ES6 中采用了 Promise/A+ 規(guī)范蹬挤。
    英文版規(guī)范: Promises/A+規(guī)范
    中文版規(guī)范: Promises/A+規(guī)范(中文)
  2. Promise標(biāo)準(zhǔn)解讀
    (1) 一個(gè)promise的當(dāng)前狀態(tài)只能是pending缚窿、fulfilledrejected三種之一。狀態(tài)改變只能是pendingfulfilled或者pendingrejected焰扳。狀態(tài)改變不可逆倦零。
    (2) promisethen方法接收兩個(gè)可選參數(shù),表示該promise狀態(tài)改變時(shí)的回調(diào)(promise.then(onFulfilled, onRejected))吨悍。then方法返回一個(gè)promise扫茅。then 方法可以被同一個(gè) promise 調(diào)用多次。

實(shí)現(xiàn)Promise

Promise標(biāo)準(zhǔn)僅描述了then方法的行為育瓜,未對(duì)catch葫隙、allrace方法進(jìn)行描述躏仇,也未規(guī)范如何創(chuàng)建一個(gè)Promise對(duì)象恋脚。ES6Promise提供了以下API腺办。
(1) 構(gòu)造函數(shù)

function Promise(resolver) {}

(2) 原型方法

Promise.prototype.then = function() {}
Promise.prototype.catch = function() {}

(3) 靜態(tài)方法

Promise.resolve = function() {}
Promise.reject = function() {}
Promise.all = function() {}
Promise.race = function() {}

構(gòu)造函數(shù)

  1. Promise/A+標(biāo)準(zhǔn)并沒有指定如何構(gòu)造一個(gè)Promise對(duì)象,我們以ES6原生Promise模塊里通過構(gòu)造函數(shù)創(chuàng)建Promise對(duì)象的方式實(shí)現(xiàn)Promise構(gòu)造函數(shù)糟描。ES6中通過構(gòu)造函數(shù)創(chuàng)建Promise對(duì)象的簡(jiǎn)單用法如下:
const promise = new Promise((resolve) => {
    setTimeout(()=> {
        resolve(1);
    }, 2000);
});
promise.then(a=> alert(a));
promise.then(a => alert(a+1));

構(gòu)造函數(shù)用法總結(jié):
(1) 構(gòu)造函數(shù)接收一個(gè)executor立即執(zhí)行函數(shù)
(2) executor立即執(zhí)行函數(shù)接收一個(gè)resolve函數(shù)
(3) promise對(duì)象的then方法綁定狀態(tài)變?yōu)?code>fulfilled時(shí)的回調(diào)
(4) resolve函數(shù)被調(diào)用時(shí)會(huì)觸發(fā)then方法中的回調(diào)

  1. 構(gòu)造函數(shù)的簡(jiǎn)單實(shí)現(xiàn)
function Promise(executor) {
    var self = this;
    self.status = 'pending'; //promise當(dāng)前的狀態(tài)
    self.data = undefined; //promise的值
    self.onResolvedCallback = [];
    //promise狀態(tài)變?yōu)閞esolve時(shí)的回調(diào)函數(shù)集怀喉,可能有多個(gè)
   function resolve(value) {
       if(self.status === 'pending') {
           self.status = 'resolved';
           self.data = value;
           for(var i = 0; i < self.onResolvedCallback.length; i++) {
               self.onResolvedCallback[i](value);
           }
       }
   }
   executor(resolve);
};
Promise.prototype.then = function (resolve) {
    this.onResolvedCallback.push(resolve);
};
  1. executor自執(zhí)行函數(shù)接收的第二個(gè)參數(shù)為reject函數(shù)且reject函數(shù)在promise對(duì)象狀態(tài)變?yōu)?code>rejected時(shí)或executor拋出異常時(shí)觸發(fā)。
function Promise(executor) {
    var self = this;
    self.status = 'pending'; //promise當(dāng)前的狀態(tài)
    self.data = undefined; //promise的值
    self.onResolvedCallback = [];
    //promise狀態(tài)變?yōu)閞esolve時(shí)的回調(diào)函數(shù)集船响,可能有多個(gè)
    self.onRejectedCallback = [];
    //promise狀態(tài)變?yōu)閞eject時(shí)的回調(diào)函數(shù)集躬拢,可能有多個(gè)
   function resolve(value) {
       if(self.status === 'pending') {
           self.status = 'resolved';
           self.data = value;
           for(var i = 0; i < self.onResolvedCallback.length; i++) {
               self.onResolvedCallback[i](value);
           }
       }
   }

   function reject(reason) {
        if(self.status === 'pending') {
            self.status = 'rejected';
            self.data = reason;
            for(var i = 0; i < self.onRejectedCallback.length; i++) {
                self.onRejectedCallback[i](reason);
            }
        }
   }

   try {
       executor(resolve, reject);
   } catch (e){
       reject(e);
   }
};
Promise.prototype.then = function (onResolve, onReject) {
    this.onResolvedCallback.push(onResolve);
    this.onRejectedCallback.push(onReject);
};

總結(jié):①executor函數(shù)作為實(shí)參在創(chuàng)建Promise對(duì)象時(shí)傳入Promise構(gòu)造函數(shù)。②resolvereject函數(shù)作為實(shí)參傳入executor函數(shù)见间。③value作為實(shí)參傳入resolvereject函數(shù)聊闯。

  1. 如果executor自執(zhí)行函數(shù)中的resolve函數(shù)立即觸發(fā)時(shí),發(fā)現(xiàn)Promise失效米诉,例如:
const promise = new Promise((resolve) => {
    resolve(1);
});
promise.then((a) => alert(a));

解決辦法:需要將promiseresolvereject異步執(zhí)行菱蔬。

function resolve(value) {
    setTimeout(function () {
        if(self.status === 'pending') {
            self.status = 'resolved';
            self.data = value;
            for(var i = 0; i < self.onResolvedCallback.length; i++) {
                self.onResolvedCallback[i](value);
            }
        }
    })
}

function reject(reason) {
    setTimeout(function () {
        if(self.status === 'pending') {
            self.status = 'rejected';
            self.data = reason;
            for(var i = 0; i < self.onRejectedCallback.length; i++) {
                self.onRejectedCallback[i](reason);
            }
        }
    })
}

then方法

  1. 在構(gòu)造函數(shù)中的示例中,then方法并沒有返回一個(gè)promise對(duì)象荒辕,而 Promise/A+ 規(guī)范中規(guī)定then方法用來注冊(cè)promise對(duì)象狀態(tài)改變時(shí)的回調(diào)汗销,且返回一個(gè)新的promise對(duì)象。
    (1) then方法返回一個(gè)新的promise對(duì)象抵窒。
    (2) executor自執(zhí)行函數(shù)中的resolve參數(shù)調(diào)用時(shí)執(zhí)行then方法的第一個(gè)回調(diào)函數(shù)onResolved弛针。
    (3) executor自執(zhí)行函數(shù)中的reject參數(shù)調(diào)用時(shí)執(zhí)行then方法的第二個(gè)回調(diào)函數(shù)onRejected
Promise.prototype.then = function (onResolved, onRejected) {
    var self = this;
    var promise2;
    onResolved = typeof onResolved === 'function' 
                ? onResolved 
                : function (value) {return value};
    onRejected = typeof onRejected === 'function' 
                ? onRejected 
                : function (reason) {throw reason};
    //promise對(duì)象當(dāng)前狀態(tài)為resolved
    if(self.status === 'resolved') {
        return promise2 = new Promise(function (resolve, reject) {
            try {
                //調(diào)用onResolve回調(diào)函數(shù)
                var x = onResolved(self.data);
                //如果onResolve回調(diào)函數(shù)返回值為一個(gè)promise對(duì)象
                if(x instanceof  Promise) {
                    //將它的結(jié)果作為promise2的結(jié)果
                    x.then(resolve, reject);
                } else {
                    resolve(x);//執(zhí)行promise2的onResolve回調(diào)
           }        
            } catch (e) {
                reject(e); //執(zhí)行promise2的onReject回調(diào)
            }
        })
    }
    //promise對(duì)象當(dāng)前狀態(tài)為rejected
    if(self.status === 'rejected') {
        return promise2 = new Promise(function (resolve, reject) {
            try {
                var x = onRejected(self.data);
                if (x instanceof Promise) {
                    x.then(resolve, reject)
                } else {
                    resolve(x)
                }
            } catch (e) {
                reject(e)
            }
        })
    }
    //promise對(duì)象當(dāng)前狀態(tài)為pending
    //此時(shí)并不能確定調(diào)用onResolved還是onRejected李皇,需要等當(dāng)前Promise狀態(tài)確定削茁。
    //所以需要將callBack放入promise1的回調(diào)數(shù)組中
    if(self.status === 'pending') {
        return promise2 = new Promise(function (resolve, reject) {
            self.onResolvedCallback.push(function (value) {
                try {
                    var x = onResolved(self.data);
                    if (x instanceof Promise) {
                        x.then(resolve, reject);
                    } else {
                        resolve(x);
          }
                } catch (e) {
                    reject(e);
                }
            })
            self.onRejectedCallback.push(function(reason) {
                try {
                    var x = onRejected(self.data);
                    if (x instanceof Promise) {
                        x.then(resolve, reject)
                    } else {
                        resolve(x);
                    }
                } catch (e) {
                    reject(e)
                }
            })
        })
    }
};
  1. 參照Promise/A+標(biāo)準(zhǔn)對(duì)promise進(jìn)行改寫
function resolvePromise(promise2, x, resolve, reject) {
    var then
    var thenCalledOrThrow = false

    if (promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise!'))
    }
    if (x instanceof Promise) {
        if (x.status === 'pending') { //because x could resolved by a Promise Object
            x.then(function(v) {
                resolvePromise(promise2, v, resolve, reject)
            }, reject)
        } else { //but if it is resolved, it will never resolved by a Promise Object but a static value;
            x.then(resolve, reject)
        }
        return
    }

    if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {
        try {
            then = x.then //because x.then could be a getter
            if (typeof then === 'function') {
                then.call(x, function rs(y) {
                    if (thenCalledOrThrow) return
                    thenCalledOrThrow = true
                    return resolvePromise(promise2, y, resolve, reject)
                }, function rj(r) {
                    if (thenCalledOrThrow) return
                    thenCalledOrThrow = true
                    return reject(r)
                })
            } else {
                resolve(x)
            }
        } catch (e) {
            if (thenCalledOrThrow) return
            thenCalledOrThrow = true
            return reject(e)
        }
    } else {
        resolve(x)
    }
}

Promise.prototype.then = function(onResolved, onRejected) {
    var self = this
    var promise2
    onResolved = typeof onResolved === 'function' ? onResolved : function(v) {
        return v
    }
    onRejected = typeof onRejected === 'function' ? onRejected : function(r) {
        throw r
    }

    if (self.status === 'resolved') {
        return promise2 = new Promise(function(resolve, reject) {
            setTimeout(function() { // 異步執(zhí)行onResolved
                try {
                    var x = onResolved(self.data)
                    resolvePromise(promise2, x, resolve, reject)
                } catch (reason) {
                    reject(reason)
                }
            })
        })
    }

    if (self.status === 'rejected') {
        return promise2 = new Promise(function(resolve, reject) {
            setTimeout(function() { // 異步執(zhí)行onRejected
                try {
                    var x = onRejected(self.data)
                    resolvePromise(promise2, x, resolve, reject)
                } catch (reason) {
                    reject(reason)
                }
            })
        })
    }

    if (self.status === 'pending') {
        // 這里之所以沒有異步執(zhí)行,是因?yàn)檫@些函數(shù)必然會(huì)被resolve或reject調(diào)用掉房,而resolve或reject函數(shù)里的內(nèi)容已是異步執(zhí)行茧跋,構(gòu)造函數(shù)里的定義
        return promise2 = new Promise(function(resolve, reject) {
            self.onResolvedCallback.push(function(value) {
                try {
                    var x = onResolved(value)
                    resolvePromise(promise2, x, resolve, reject)
                } catch (r) {
                    reject(r)
                }
            })

            self.onRejectedCallback.push(function(reason) {
                try {
                    var x = onRejected(reason)
                    resolvePromise(promise2, x, resolve, reject)
                } catch (r) {
                    reject(r)
                }
            })
        })
    }
}

完整代碼

var Promise = (function() {
    function Promise(resolver) {
        if (typeof resolver !== 'function') { //resolver必須是函數(shù)
            throw new TypeError('Promise resolver ' + resolver + ' is not a function')
        }
        if (!(this instanceof Promise)) return new Promise(resolver)

        var self = this //保存this
        self.callbacks = [] //保存onResolve和onReject函數(shù)集合
        self.status = 'pending' //當(dāng)前狀態(tài)

        function resolve(value) {
            setTimeout(function() { //異步調(diào)用
                if (self.status !== 'pending') {
                    return
                }
                self.status = 'resolved' //修改狀態(tài)
                self.data = value

                for (var i = 0; i < self.callbacks.length; i++) {
                    self.callbacks[i].onResolved(value)
                }
            })
        }

        function reject(reason) {
            setTimeout(function(){ //異步調(diào)用
                if (self.status !== 'pending') {
                    return
                }
                self.status = 'rejected' //修改狀態(tài)
                self.data = reason

                for (var i = 0; i < self.callbacks.length; i++) {
                    self.callbacks[i].onRejected(reason)
                }
            })
        }

        try{
            resolver(resolve, reject) //執(zhí)行resolver函數(shù)
        } catch(e) {
            reject(e)
        }
    }

    function resolvePromise(promise, x, resolve, reject) {
        var then
        var thenCalledOrThrow = false

        if (promise === x) {
            return reject(new TypeError('Chaining cycle detected for promise!'))
        }

        if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {
            try {
                then = x.then
                if (typeof then === 'function') {
                    then.call(x, function rs(y) {
                        if (thenCalledOrThrow) return
                        thenCalledOrThrow = true
                        return resolvePromise(promise, y, resolve, reject)
                    }, function rj(r) {
                        if (thenCalledOrThrow) return
                        thenCalledOrThrow = true
                        return reject(r)
                    })
                } else {
                    return resolve(x)
                }
            } catch(e) {
                if (thenCalledOrThrow) return
                thenCalledOrThrow = true
                return reject(e)
            }
        } else {
            return resolve(x)
        }
    }

    Promise.prototype.then = function(onResolved, onRejected) {
        //健壯性處理,處理點(diǎn)擊穿透
        onResolved = typeof onResolved === 'function' ? onResolved : function(v){return v}
        onRejected = typeof onRejected === 'function' ? onRejected : function(r){throw r}
        var self = this
        var promise2

        //promise狀態(tài)為resolved
        if (self.status === 'resolved') {
            return promise2 = new Promise(function(resolve, reject) {
                setTimeout(function() {
                    try {
                        //調(diào)用then方法的onResolved回調(diào)
                        var x = onResolved(self.data)
                        //根據(jù)x的值修改promise2的狀態(tài)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch(e) {
                        //promise2狀態(tài)變?yōu)閞ejected
                        return reject(e)
                    }
                })
            })
        }

        //promise狀態(tài)為rejected
        if (self.status === 'rejected') {
            return promise2 = new Promise(function(resolve, reject) {
                setTimeout(function() {
                    try {
                        //調(diào)用then方法的onReject回調(diào)
                        var x = onRejected(self.data)
                        //根據(jù)x的值修改promise2的狀態(tài)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch(e) {
                        //promise2狀態(tài)變?yōu)閞ejected
                        return reject(e)
                    }
                })
            })
        }

        //promise狀態(tài)為pending
        //需要等待promise的狀態(tài)改變
        if (self.status === 'pending') {
            return promise2 = new Promise(function(resolve, reject) {
                self.callbacks.push({
                    onResolved: function(value) {
                        try {
                            //調(diào)用then方法的onResolved回調(diào)
                            var x = onResolved(value)
                            //根據(jù)x的值修改promise2的狀態(tài)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch(e) {
                            //promise2狀態(tài)變?yōu)閞ejected
                            return reject(e)
                        }
                    },
                    onRejected: function(reason) {
                        try {
                            //調(diào)用then方法的onResolved回調(diào)
                            var x = onRejected(reason)
                            //根據(jù)x的值修改promise2的狀態(tài)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch(e) {
                            //promise2狀態(tài)變?yōu)閞ejected
                            return reject(e)
                        }
                    }
                })
            })
        }
    }

    //獲取當(dāng)前Promise傳遞的值
    Promise.prototype.valueOf = function() {
        return this.data
    }

    //由then方法實(shí)現(xiàn)catch方法
    Promise.prototype.catch = function(onRejected) {
        return this.then(null, onRejected)
    }

    //finally方法
    Promise.prototype.finally = function(fn) {
        return this.then(function(v){
            setTimeout(fn)
            return v
        }, function(r){
            setTimeout(fn)
            throw r
        })
    }

    Promise.prototype.spread = function(fn, onRejected) {
        return this.then(function(values) {
            return fn.apply(null, values)
        }, onRejected)
    }

    Promise.prototype.inject = function(fn, onRejected) {
        return this.then(function(v) {
            return fn.apply(null, fn.toString().match(/\((.*?)\)/)[1].split(',').map(function(key){
                return v[key];
            }))
        }, onRejected)
    }

    Promise.prototype.delay = function(duration) {
        return this.then(function(value) {
            return new Promise(function(resolve, reject) {
                setTimeout(function() {
                    resolve(value)
                }, duration)
            })
        }, function(reason) {
            return new Promise(function(resolve, reject) {
                setTimeout(function() {
                    reject(reason)
                }, duration)
            })
        })
    }

    Promise.all = function(promises) {
        return new Promise(function(resolve, reject) {
            var resolvedCounter = 0
            var promiseNum = promises.length
            var resolvedValues = new Array(promiseNum)
            for (var i = 0; i < promiseNum; i++) {
                (function(i) {
                    Promise.resolve(promises[i]).then(function(value) {
                        resolvedCounter++
                        resolvedValues[i] = value
                        if (resolvedCounter == promiseNum) {
                            return resolve(resolvedValues)
                        }
                    }, function(reason) {
                        return reject(reason)
                    })
                })(i)
            }
        })
    }

    Promise.race = function(promises) {
        return new Promise(function(resolve, reject) {
            for (var i = 0; i < promises.length; i++) {
                Promise.resolve(promises[i]).then(function(value) {
                    return resolve(value)
                }, function(reason) {
                    return reject(reason)
                })
            }
        })
    }

    Promise.resolve = function(value) {
        var promise = new Promise(function(resolve, reject) {
            resolvePromise(promise, value, resolve, reject)
        })
        return promise
    }

    Promise.reject = function(reason) {
        return new Promise(function(resolve, reject) {
            reject(reason)
        })
    }

    Promise.fcall = function(fn){
        // 雖然fn可以接收到上一層then里傳來的參數(shù)卓囚,但是其實(shí)是undefined瘾杭,所以跟沒有是一樣的,因?yàn)閞esolve沒參數(shù)啊
        return Promise.resolve().then(fn)
    }

    Promise.done = Promise.stop = function(){
        return new Promise(function(){})
    }

    Promise.deferred = Promise.defer = function() {
        var dfd = {}
        dfd.promise = new Promise(function(resolve, reject) {
            dfd.resolve = resolve
            dfd.reject = reject
        })
        return dfd
    }

    try { // CommonJS compliance
        module.exports = Promise
    } catch(e) {}

    return Promise
})()

參考

Promise實(shí)現(xiàn)分析
Promise完整代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哪亿,一起剝皮案震驚了整個(gè)濱河市粥烁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蝇棉,老刑警劉巖讨阻,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異篡殷,居然都是意外死亡钝吮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奇瘦,“玉大人棘催,你說我怎么就攤上這事×椿迹” “怎么了巧鸭?”我有些...
    開封第一講書人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵瓶您,是天一觀的道長(zhǎng)麻捻。 經(jīng)常有香客問我,道長(zhǎng)呀袱,這世上最難降的妖魔是什么贸毕? 我笑而不...
    開封第一講書人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮夜赵,結(jié)果婚禮上明棍,老公的妹妹穿的比我還像新娘。我一直安慰自己寇僧,他們只是感情好摊腋,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嘁傀,像睡著了一般兴蒸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上细办,一...
    開封第一講書人閱讀 52,196評(píng)論 1 308
  • 那天橙凳,我揣著相機(jī)與錄音,去河邊找鬼笑撞。 笑死岛啸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的茴肥。 我是一名探鬼主播坚踩,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼瓤狐!你這毒婦竟也來了瞬铸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤芬首,失蹤者是張志新(化名)和其女友劉穎赴捞,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體郁稍,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赦政,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恢着。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桐愉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掰派,到底是詐尸還是另有隱情从诲,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布靡羡,位于F島的核電站系洛,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏略步。R本人自食惡果不足惜描扯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望趟薄。 院中可真熱鬧绽诚,春花似錦、人聲如沸杭煎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽羡铲。三九已至蜂桶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間犀勒,已是汗流浹背屎飘。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贾费,地道東北人钦购。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像褂萧,于是被迫代替她去往敵國(guó)和親押桃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 本文適用的讀者 本文寫給有一定Promise使用經(jīng)驗(yàn)的人导犹,如果你還沒有使用過Promise唱凯,這篇文章可能不適合你,...
    HZ充電大喵閱讀 7,313評(píng)論 6 19
  • title: promise總結(jié) 總結(jié)在前 前言 下文類似 Promise#then谎痢、Promise#resolv...
    JyLie閱讀 12,259評(píng)論 1 21
  • Promise 對(duì)象 Promise 的含義 Promise 是異步編程的一種解決方案磕昼,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,708評(píng)論 1 56
  • 排版很不友好,抱歉 /* * 實(shí)現(xiàn)Promise是根據(jù)Promise規(guī)范來的:https://promisesap...
    Egde閱讀 1,493評(píng)論 0 0
  • 親愛的果果: 如你所說节猿,今天真是快樂的一天票从,我們做了好多有意義使自己成長(zhǎng)的事漫雕! 奧數(shù)課你今天比較專注,...
    熱帶毛毛蟲閱讀 252評(píng)論 1 3