前言
本文旨在簡(jiǎn)單講解一下javascript中的Promise對(duì)象的概念,特性與簡(jiǎn)單的使用方法。并在文末會(huì)附上一份符合PromiseA+規(guī)范的Promise對(duì)象的完整實(shí)現(xiàn)。
注:本文中的相關(guān)概念均基于PromiseA+規(guī)范。
相關(guān)參考
正文
1.Promise簡(jiǎn)介
在了解javescript中的Promise實(shí)現(xiàn)之前有必要先了解一下Promise的概念。
什么是Promise?
關(guān)于Promise概念的解釋,網(wǎng)上的各種資料眾說(shuō)紛紜,這里奉上筆者自己的理解。簡(jiǎn)單來(lái)說(shuō),Promise就是一套處理異步事件的方式和流程。promise在英文中的含義是約定,而針對(duì)異步事件特性的處理方式與這個(gè)含義非常吻合。
為什么要使用Promise?
一個(gè)異步事件不會(huì)立刻返回結(jié)果,這時(shí)我們就需要預(yù)先規(guī)定一些操作,等待異步事件返回結(jié)果后,再去使用某種方式讓預(yù)先規(guī)定的操作執(zhí)行。在javascript的習(xí)慣中,我們常用回調(diào)函數(shù)(callback)去實(shí)現(xiàn)上述過(guò)程。下面是一個(gè)簡(jiǎn)單的示例:
例1
let asyncFunc = function(callback){
? ? let num = 100;
? ? setTimeout(function(){
? ? ? ? num += 100;
? ? ? ? callback(num);
? ? },2000);
};
function foo(value){
? ? console.log(value);? //value => 200
}
asyncFunc (foo);
上面就是一個(gè)簡(jiǎn)單的異步操作處理過(guò)程,asyncFunc就是一個(gè)異步的函數(shù),執(zhí)行后通過(guò)setTimeout方法在2秒返回了一個(gè)值,而foo則是一個(gè)回調(diào)函數(shù),通過(guò)傳入異步函數(shù)并且在返回結(jié)果后被調(diào)用的方式獲取異步操作的結(jié)果。這里的回調(diào)函數(shù)就如同一個(gè)事先的約定,在異步操作返回結(jié)果后立即被實(shí)現(xiàn)。
那么,既然js中已經(jīng)有處理異步事件的方法,為何還要引入Promise這個(gè)新的方式呢?實(shí)際上,上面這段代碼只是簡(jiǎn)單展示下回調(diào)函數(shù)的基礎(chǔ)使用,而在真正的使用場(chǎng)景中,我們不得不面對(duì)各種十分復(fù)雜的局面。通常在一個(gè)異步操作返回結(jié)果后執(zhí)行的回調(diào)中還要進(jìn)行另一個(gè)異步操作,而同一個(gè)異步操作返回結(jié)果后要執(zhí)行的回調(diào)函數(shù)可不止一個(gè)。數(shù)個(gè)異步操作與回調(diào)函數(shù)彼此嵌套,時(shí)刻挑戰(zhàn)者維護(hù)和使用者的神經(jīng)。下面是一個(gè)彼此嵌套的例子:
例2
ajax(url1,function(value1){
? ? foo(value1);
? ? bar();
});
function foo(value){
? ? ajax(url2,function(value2){
? ? ? ? do something..
? ? ? ? ajax(url3,function(value3){
? ? ? ? ? ? ...
? ? ? ? })
? ? });
}
function bar(){ do something.. };
上面的例子模擬了一個(gè)js中一個(gè)常用的異步操作:發(fā)送ajax請(qǐng)求數(shù)據(jù)。在url1請(qǐng)求的回調(diào)中使用了foo和bar兩個(gè)函數(shù),而foo中又發(fā)送了url2,url3的請(qǐng)求。。。這樣數(shù)層嵌套下來(lái),最終導(dǎo)致代碼非常的不直觀,維護(hù)起來(lái)難度也直線上升,形成常說(shuō)的“回調(diào)地獄”。
了解了傳統(tǒng)上js處理異步操作的復(fù)雜和困難后,我們不禁思索,是否有方法能夠更加簡(jiǎn)潔,直觀的去解決異步操作的種種問題?答案就是我們這篇文章的主角:Promise。
2. Promise的特性及使用
在PromiseA+規(guī)范中做出了這樣定義:promise是一個(gè)包含了兼容Promise規(guī)范then方法的對(duì)象或函數(shù),與Promise最主要的交互方法是通過(guò)將函數(shù)傳入它的then方法從而獲取得Promise最終的值或Promise最終最拒絕(reject)的原因。
? 這段定義有兩個(gè)重點(diǎn):1.Promise是一個(gè)對(duì)象或函數(shù)? 2.它有一個(gè)then方法,能夠獲取prmose的最終結(jié)果。下面我們就來(lái)實(shí)際看一下Promise到底是如何處理異步事件的,我們將上面的例1使用Promise進(jìn)行一下改寫:
例3
let p = new Promise(function(resolve,reject){
? ? let value = 100;
? ? setTimeout(function(){
? ? ? ? value += 100;
? ? ? ? resolve(value);
? ? },2000);
});
p.then(function(value){
? ? console.log(value);? ? ? //value => 200
},function(err){
? ? do something...
});
初看之下其實(shí)并沒有太大區(qū)別,但實(shí)際上Promise的威力在更復(fù)雜的場(chǎng)景下才能更好的發(fā)揮。我們先針對(duì)這個(gè)簡(jiǎn)單的例子來(lái)講解下Promise的使用
首先通過(guò) new 關(guān)鍵字實(shí)例化一個(gè)Promise對(duì)象,在這個(gè)對(duì)象中傳入一個(gè)要執(zhí)行異步操作的函數(shù)。這個(gè)函數(shù)包含兩個(gè)形參:resolve和reject。這兩個(gè)形參是Promise中定義的2個(gè)函數(shù),分別在異步事件成功和失敗時(shí)調(diào)用。例3中我們?cè)?秒后調(diào)用了resolve函數(shù),代表著異步事件成功,返回一個(gè)值。而在我們實(shí)例化Promise對(duì)象的同時(shí),我們又調(diào)用了這個(gè)實(shí)例的then方法。then方法可以說(shuō)是Promise方法中的核心,它即代表著Promise約定的這層含義,在then方法中接收2個(gè)函數(shù)作為參數(shù),分別在異步事件成功時(shí)或失敗時(shí)執(zhí)行,并且兩個(gè)函數(shù)的參數(shù)正是異步事件成功時(shí)返回的值或失敗時(shí)原因。
其實(shí),使用Promise對(duì)象來(lái)處理異步事件比起使用傳統(tǒng)的回調(diào)函數(shù)的一個(gè)優(yōu)點(diǎn)在于:Promise規(guī)范了處理異步事件的流程。我們不必再深入異步事件的內(nèi)部,去分析種種狀態(tài)變化后對(duì)應(yīng)的回調(diào)究竟如何調(diào)用,也不必過(guò)多考慮異步事件內(nèi)部發(fā)生錯(cuò)誤時(shí)該如何捕獲,我們只需要在合適的時(shí)候通知Promise返回成功或失敗狀態(tài),剩下的事統(tǒng)統(tǒng)交給Promise去解決。
以上我們大致了解了Promise的處理流程,在詳細(xì)講解Promise對(duì)象中的方法之前有必要先了解一下Promise的狀態(tài)概念。
一個(gè)Promise對(duì)象在實(shí)例化后可能擁有以下3種狀態(tài)的其中之一:
Fulfilled - 當(dāng)傳入的異步事件成功返回值時(shí)的狀態(tài)
Rejected - 當(dāng)傳入的異步事件失敗或產(chǎn)生異常時(shí)的狀態(tài)
Pending -? 當(dāng)傳入的異步事件還沒有結(jié)果返回時(shí)的狀態(tài)
注意,任何時(shí)候Promise對(duì)象都只能處于以上其中狀態(tài)的一種,當(dāng)Promise對(duì)象處于Pending狀態(tài)時(shí),它可以轉(zhuǎn)化成Fulfilled 或Rejected 狀態(tài),而當(dāng)Promise對(duì)象處于Fulfilled 或Rejected狀態(tài)時(shí),它不能再轉(zhuǎn)化成其他狀態(tài)。
可以用一張圖來(lái)直白的表示上面這段話
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(圖片取自Promise迷你書)
在了解了Promise的三種狀態(tài)后 ,接下來(lái)可以詳細(xì)了解下Promise對(duì)象的幾個(gè)方法
resolve()
resolve方法是在一個(gè)Promise對(duì)象實(shí)例化時(shí)傳入的任務(wù)函數(shù)的第一個(gè)參數(shù),它的作用是讓Promise進(jìn)入“Fulfilled ”狀態(tài),resolve方法只接受一個(gè)參數(shù),即異步事件的返回值value。
reject()
reject方法與resolve方法正好相反,它是在一個(gè)Promise對(duì)象實(shí)例化時(shí)傳入的任務(wù)函數(shù)的第二個(gè)參數(shù),它的作用是讓Promise進(jìn)入“Rejected”狀態(tài),reject方法同樣只接受一個(gè)參數(shù),即異步事件失敗或異常的原因reason。
Promise.prototype.then()
then方法是Promise對(duì)象方法的重中之重,它是Promise實(shí)例的方法,用來(lái)注冊(cè)Promise對(duì)象成功時(shí)執(zhí)行的回調(diào)函數(shù)(onFulfilled)和失敗時(shí)執(zhí)行的回調(diào)函數(shù)(onRejected)。一個(gè)then方法的返回值仍然是一個(gè)Promsie對(duì)象。因此,then方法支持鏈?zhǔn)秸{(diào)用,也就是一個(gè)一個(gè)then方法的返回值可以繼續(xù)調(diào)用then。而相鏈接的then方法中,在上一個(gè)then方法的onFulfilled或onRejected回調(diào)函數(shù)中通過(guò) return value(reason)的方式,把這個(gè)結(jié)果作為下一個(gè)then中的回調(diào)函數(shù)的參數(shù)被接收。onFulfilled和onRejected函數(shù)的返回值可以是任何javascript值,甚至一個(gè)Promise對(duì)象的成功或失敗時(shí)的回調(diào)函數(shù)可以返回一個(gè)新的Promise對(duì)象。這樣的特性使得例2中那種復(fù)雜的異步事件嵌套的場(chǎng)景處理得以簡(jiǎn)化。下面是使用Promise來(lái)重寫的例2:
例4
let p1 = new Promise(function(resolve,reject){
? ? ajax(url1,function(value1){
? ? ? ? resolve(value1);
? ? });
});
p1.then(function(value1){
? ? return new Promise(function(resolve,reject){
? ? ? ? ajax(url2,function(value2){
? ? ? ? ? ? do something..
? ? ? ? ? ? resolve(value2);
? ? ? ? });
? ? })
}).then(function(value2){
? ? return new Promise(function(resolve,reject){
? ? ? ? ajax(url3,function(value3){
? ? ? ? ? ? ...
? ? ? ? });
? ? })
});
p1.then(bar);
function bar(){do something...};
可以看出,使用Promise改寫后的代碼結(jié)構(gòu)上更加清晰,它把層層嵌套的函數(shù)轉(zhuǎn)化成鏈?zhǔn)降恼{(diào)用then方法的形式,這樣可以非常清晰的看出事件間的關(guān)系和執(zhí)行順序,大大降低了日后代碼使用和維護(hù)的難度。
關(guān)于then方法還有幾點(diǎn)補(bǔ)充:
1. then方法中的onFulfilled和onRejected方法都是可以省略的。
2. 當(dāng)一個(gè)Promise失敗返回了reason,而then方法中沒有定義onRejected函數(shù)時(shí),這個(gè)reason會(huì)被鏈?zhǔn)秸{(diào)用的下一個(gè)then方法的onRejected方法接收。
3. 一個(gè)Promise實(shí)例可以調(diào)用多次then方法,這些then注冊(cè)的onFulfilled和onRejected函數(shù)會(huì)按照注冊(cè)的順序執(zhí)行。
Promise.prototype.catch()
catch方法是一個(gè)then方法的語(yǔ)法糖,它只接受一個(gè)失敗處理函數(shù)onRejected,實(shí)際上等同于以下代碼:
new Promsie.then(null,function(){
? ? do something...
})
Promise.all()
all方法是Promsie對(duì)象的靜態(tài)方法,使用方式是 Promise.all()。all方法接收的參數(shù)為一個(gè)包含數(shù)個(gè)Promise對(duì)象實(shí)例的數(shù)組,并返回一個(gè)新的Promise實(shí)例。當(dāng)數(shù)組中所有的Promse實(shí)例都返回結(jié)果后,將所有數(shù)組中的Promise實(shí)例的成功返回值傳入一個(gè)數(shù)組,并將這個(gè)數(shù)組注入到all方法返回的新實(shí)例的then方法中。下面是一個(gè)all方法的使用實(shí)例:
例5
let promiseArr = [
? ? new Promise(function(resolve,reject){
? ? ? ? setTimeout(function(){
? ? ? ? ? ? resolve(100)
? ? ? ? },1000)
? ? }),
? ? new Promise(function(resolve,reject){
? ? ? ? setTimeout(function(){
? ? ? ? ? ? resolve(200)
? ? ? ? },500)
? ? })
]
Promise.all(promiseArr).then(function(valArr){
? ? console.log(valArr)? ? // valArr? => [100,200]
},function(err){
? ? do something...
})
all方法值得注意的有兩點(diǎn):
1.數(shù)組中所有promise實(shí)例都成功后的返回值,在valArr中的順序是按照promiseArr 中promise實(shí)例的順序來(lái)排列的。
2.當(dāng)任何一個(gè)promise失敗后,all方法直接將返回的Promise對(duì)象的狀態(tài)變?yōu)镽ejected,并調(diào)用then方法的onRejected函數(shù),把失敗的原因傳遞出來(lái)。
Promise.resolve()
Promsie對(duì)象本身存在一個(gè)resolve方法,它的作用是立刻返回一個(gè)狀態(tài)為Fulfilled的Promise對(duì)象實(shí)例。如果你在這個(gè)resolve方法中傳入的是一個(gè)Promise實(shí)例的話,那么resolve方法會(huì)保持這個(gè)Promise實(shí)例的狀態(tài),并根據(jù)它最后返回的狀態(tài)來(lái)調(diào)用resolve方法返回的Promise實(shí)例then方法的onResolve或onRejected函數(shù)。
其實(shí)這個(gè)方法最常用的場(chǎng)景是講一個(gè)普通的值轉(zhuǎn)換成一個(gè)Promise實(shí)例。一般來(lái)說(shuō)不是很常用。
Promise.reject()
與Promise.resolve()相反,它的作用是立刻返回一個(gè)狀態(tài)為Rejected的Promise對(duì)象實(shí)例。實(shí)際上這個(gè)方法是一個(gè)語(yǔ)法糖,它等同于以下代碼:
new Promise(function(resolve,reject){
? ? reject(reason);
})
以上就是一個(gè)ES6中的Promise對(duì)象中所包含的常用方法。
3. 一個(gè)符合PromiseA+規(guī)范的Promise對(duì)象的完整實(shí)現(xiàn)
? 想必看到這里的一些讀者會(huì)不禁思考,Promise對(duì)象究竟是如何實(shí)現(xiàn)的呢?我個(gè)人參考了一些資料實(shí)現(xiàn)了一個(gè)符合PromiseA+規(guī)范的Promise對(duì)象,把源代碼貼在下面,有興趣的朋友可以參考一下,實(shí)際上代碼本身并不是很多,各位看完以后可以嘗試用自己的方式再實(shí)現(xiàn)一遍。同時(shí)附上一個(gè)測(cè)試工具,里面包含了幾百個(gè)測(cè)試用例,用來(lái)測(cè)試我們自己寫的Promise是否完美的符合PromiseA+規(guī)范。
使用的方法很簡(jiǎn)單
npm i -g promises-aplus-tests
promises-aplus-tests Promise.js
安裝后運(yùn)行你的js文件就可以測(cè)試你的代碼是否符合規(guī)范了。
下面就是我實(shí)現(xiàn)的Promise對(duì)象的代碼
function MyPromise(task) {
? ? const _this = this;
? ? _this.status = 'pending';? //設(shè)定初始狀態(tài)
? ? _this.value = undefined;
? ? _this.onFulfilledsList = [];? //onFulfilled函數(shù)序列
? ? _this.onRejectedsList = [];? //onRejected函數(shù)序列
? ? function resolve(value) {
? ? ? ? if (value instanceof MyPromise) {
? ? ? ? ? ? return value.then(resolve, reject);
? ? ? ? }
? ? ? ? //異步執(zhí)行resolve或reject方法,保證代碼的統(tǒng)一性和注冊(cè)的回調(diào)函數(shù)按照正確的順序執(zhí)行
? ? ? ? ? ? if (_this.status === 'pending') {
? ? ? ? ? ? ? ? _this.status = 'fulfilled';
? ? ? ? ? ? ? ? _this.value = value;
? ? ? ? ? ? ? ? _this.onFulfilledsList.forEach(cb => cb(value))
? ? ? ? ? ? }
? ? }
? ? function reject(reason) {
? ? ? ? ? ? if (_this.status === 'pending') {
? ? ? ? ? ? ? ? _this.status = 'rejected';
? ? ? ? ? ? ? ? _this.reason = reason;
? ? ? ? ? ? ? ? _this.onRejectedsList.forEach(cb => cb(reason))
? ? ? ? ? ? }
? ? }
? ? try {
? ? ? ? task(resolve, reject);
? ? } catch (err) {
? ? ? ? throw new Error(err);
? ? }
}
function resolvePromise(promise2, x, resolve, reject) {
? ? if (x === promise2) {
? ? ? ? return reject(new TypeError('循環(huán)引用'));
? ? }
? ? //如果返回的是一個(gè)thenable對(duì)象,即一個(gè)擁有then方法的對(duì)象,那么使用它的then方法去獲得它的最終返回值。目的是為了兼容其他Promise庫(kù)
? ? if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
? ? ? ? let then, called;
? ? ? ? try {
? ? ? ? ? ? then = x.then;
? ? ? ? ? ? if (typeof then === 'function') {
? ? ? ? ? ? ? ? then.call(x, function (newx) {
? ? ? ? ? ? ? ? ? ? if (called) return;? //防止重復(fù)調(diào)用
? ? ? ? ? ? ? ? ? ? called = true;
? ? ? ? ? ? ? ? ? ? resolvePromise(promise2, newx, resolve, reject);
? ? ? ? ? ? ? ? }, function (err) {
? ? ? ? ? ? ? ? ? ? if (called) return;
? ? ? ? ? ? ? ? ? ? called = true;
? ? ? ? ? ? ? ? ? ? return reject(err);
? ? ? ? ? ? ? ? });
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? resolve(x);
? ? ? ? ? ? }
? ? ? ? } catch (err) {
? ? ? ? ? ? if (called) return;
? ? ? ? ? ? called = true;
? ? ? ? ? ? reject(err);
? ? ? ? }
? ? } else {
? ? ? ? resolve(x);
? ? }
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {
? ? const _this = this;
? ? let promise2;
? ? onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (data) {
? ? ? ? return data;
? ? };
? ? onRejected = typeof onRejected === 'function' ? onRejected : function (data) {
? ? ? ? throw data;
? ? };
? ? //為了支持同步代碼,當(dāng)then方法注冊(cè)的時(shí)候如果Promise的狀態(tài)已經(jīng)改變,那么立即執(zhí)行對(duì)應(yīng)的函數(shù)
? ? if (_this.status === 'fulfilled') {
? ? ? ? promise2 = new MyPromise(function (resolve, reject) {
? ? ? ? ? setTimeout(function () {
? ? ? ? ? ? let x;
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? x = onFulfilled(_this.value);
? ? ? ? ? ? ? ? resolvePromise(promise2, x, resolve, reject);
? ? ? ? ? ? } catch (err) {
? ? ? ? ? ? ? ? reject(err);
? ? ? ? ? ? }
? ? ? ? ? })
? ? ? ? })
? ? }
? ? if (_this.status === 'rejected') {
? ? ? ? promise2 = new MyPromise(function (resolve, reject) {
? ? ? ? ?setTimeout(function () {
? ? ? ? ? ? let x;
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? x = onRejected(_this.reason);
? ? ? ? ? ? ? ? resolvePromise(promise2, x, resolve, reject);
? ? ? ? ? ? } catch (err) {
? ? ? ? ? ? ? ? reject(err);
? ? ? ? ? ? }
? ? ? ? ?)}
? ? ? ? })
? ? }
? ? if (_this.status === 'pending') {
? ? ? ? promise2 = new MyPromise(function (resolve, reject) {
? ? ? ? ? ? _this.onFulfilledsList.push(function (value) {
? ? ? ? ????????setTimeout(function () {
? ? ? ? ? ? ? ? let x;
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? x = onFulfilled(value);
? ? ? ? ? ? ? ? ? ? resolvePromise(promise2, x, resolve, reject);
? ? ? ? ? ? ? ? } catch (err) {
? ? ? ? ? ? ? ? ? ? reject(err);
? ? ? ? ? ? ? ? }
????????????????})
? ? ? ? ? ? });
? ? ? ? ? ? _this.onRejectedsList.push(function (reason) {
? ? ? ? ? ? ? ?setTimeout(function () {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? let x = onRejected(reason);
? ? ? ? ? ? ? ? ? ? resolvePromise(promise2, x, resolve, reject);
? ? ? ? ? ? ? ? } catch (err) {
? ? ? ? ? ? ? ? ? ? reject(err);
? ? ? ? ? ? ? ? }
????????????})
????????});
? ? ? ? })
? ? }
? ? return promise2;? //返回一個(gè)新的Promise實(shí)例,以便支持鏈?zhǔn)秸{(diào)用
};
MyPromise.prototype.catch = function (onRejected) {
? ? this.then(null, onRejected);
};
MyPromise.all = function (someValue) {
? ? let resolveValArr = [];
? ? let count = promiseLen = 0;
? ? let promise2;
? ? promise2 = new MyPromise(function (resolve, reject) {
? ? ? ? let iNow = 0;
? ? ? ? try {
? ? ? ? ? ? for (let item of someValue) {
? ? ? ? ? ? ? ? if (item !== null && typeof item === "object") {
? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? let then = item.then;
? ? ? ? ? ? ? ? ? ? ? ? let index = iNow;
? ? ? ? ? ? ? ? ? ? ? ? if (typeof then === 'function') {
? ? ? ? ? ? ? ? ? ? ? ? ? ? promiseLen++;
? ? ? ? ? ? ? ? ? ? ? ? ? ? then.call(item, function (value) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? resolveValArr[index] = value;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (++count === promiseLen) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? resolve(resolveValArr)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? }, function (err) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? reject(err);
? ? ? ? ? ? ? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? } catch (err) {
? ? ? ? ? ? ? ? ? ? ? ? resolveValArr[iNow] = item;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? resolveValArr[iNow] = item;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? iNow++;
? ? ? ? ? ? }
? ? ? ? ? ? if (iNow === 0) {
? ? ? ? ? ? ? ? return resolve(someValue);
? ? ? ? ? ? }
? ? ? ? ? ? if (promiseLen === 0) {
? ? ? ? ? ? ? ? return resolve(resolveValArr);
? ? ? ? ? ? }
? ? ? ? } catch (err) {
? ? ? ? ? ? reject(new TypeError('無(wú)法遍歷的類型!'));
? ? ? ? }
? ? });
? ? return promise2;
};
MyPromise.race = function (someValue) {
? ? let promise2;
? ? promise2 = new MyPromise(function (resolve, reject) {
? ? ? ? let iNow = 0;
? ? ? ? try {
? ? ? ? ? ? for (let item of someValue) {
? ? ? ? ? ? ? ? if (item !== null && typeof item === "object") {
? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? let then = item.then;
? ? ? ? ? ? ? ? ? ? ? ? then.call(item, function (value) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? resolve(value);
? ? ? ? ? ? ? ? ? ? ? ? }, function (err) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? reject(err);
? ? ? ? ? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? ? ? } catch (err) {
? ? ? ? ? ? ? ? ? ? ? ? resolve(item);
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? resolve(item);
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? iNow++;
? ? ? ? ? ? }
? ? ? ? ? ? if (iNow === 0) {
? ? ? ? ? ? ? ? return resolve(someValue);
? ? ? ? ? ? }
? ? ? ? } catch (err) {
? ? ? ? ? ? reject(new TypeError('無(wú)法遍歷的類型!'));
? ? ? ? }
? ? });
? ? return promise2;
};
MyPromise.resolve = function (value) {
? ? let promise2;
? ? if (value !== null && (typeof value === 'object' || typeof value === 'function')) {
? ? ? ? promise2 = new MyPromise(function (resolve, reject) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? let then = value.then;
? ? ? ? ? ? ? ? if (typeof value.then === 'function') {
? ? ? ? ? ? ? ? ? ? then.call(value, function (data) {
? ? ? ? ? ? ? ? ? ? ? ? resolve(data);
? ? ? ? ? ? ? ? ? ? }, reject);
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? resolve(value);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } catch (err) {
? ? ? ? ? ? ? ? reject(err);
? ? ? ? ? ? }
? ? ? ? })
? ? } else {
? ? ? ? promise2 = new MyPromise(function (resolve) {
? ? ? ? ? ? resolve(value);
? ? ? ? })
? ? }
? ? return promise2;
};
MyPromise.reject = function (reason) {
? ? return new MyPromise(function (resolve, reject) {
? ? ? ? reject(reason);
? ? })
};
module.exports = MyPromise;
//這是為了讓代碼能夠測(cè)試而開放的接口,詳見promises-aplus-tests中的相關(guān)描述
MyPromise.deferred = MyPromise.defer = function () {
? ? let deferred = {};
? ? deferred.promise = new MyPromise(function (resolve, reject) {
? ? ? ? deferred.resolve = resolve;
? ? ? ? deferred.reject = reject;
? ? });
? ? return deferred
};
尾聲
本文參考了很多資料,如果你看到其他文章有類似的觀點(diǎn)非常正常,不過(guò)筆者盡量使用了自己的理解去闡述Promise的相關(guān)知識(shí)。如果你發(fā)現(xiàn)本文中有哪些疏漏,歡迎發(fā)私信給我進(jìn)行斧正。同時(shí)也可以在下面留言給我,我會(huì)一一查看,盡量回復(fù)。