前言
本文旨在簡單講解一下javascript中的Promise對象的概念,特性與簡單的使用方法造挽。并在文末會(huì)附上一份符合PromiseA+規(guī)范的Promise對象的完整實(shí)現(xiàn)碱璃。
注:本文中的相關(guān)概念均基于PromiseA+規(guī)范。
相關(guān)參考
正文
1.Promise簡介
在了解javescript中的Promise實(shí)現(xiàn)之前有必要先了解一下Promise的概念饭入。
什么是Promise嵌器?
關(guān)于Promise概念的解釋,網(wǎng)上的各種資料眾說紛紜谐丢,這里奉上筆者自己的理解爽航。簡單來說,Promise就是一套處理異步事件的方式和流程乾忱。promise在英文中的含義是約定讥珍,而針對異步事件特性的處理方式與這個(gè)含義非常吻合。
為什么要使用Promise窄瘟?
一個(gè)異步事件不會(huì)立刻返回結(jié)果串述,這時(shí)我們就需要預(yù)先規(guī)定一些操作,等待異步事件返回結(jié)果后寞肖,再去使用某種方式讓預(yù)先規(guī)定的操作執(zhí)行纲酗。在javascript的習(xí)慣中,我們常用回調(diào)函數(shù)(callback)去實(shí)現(xiàn)上述過程新蟆。下面是一個(gè)簡單的示例:
例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è)簡單的異步操作處理過程觅赊,asyncFunc就是一個(gè)異步的函數(shù),執(zhí)行后通過setTimeout方法在2秒返回了一個(gè)值琼稻,而foo則是一個(gè)回調(diào)函數(shù)吮螺,通過傳入異步函數(shù)并且在返回結(jié)果后被調(diào)用的方式獲取異步操作的結(jié)果。這里的回調(diào)函數(shù)就如同一個(gè)事先的約定帕翻,在異步操作返回結(jié)果后立即被實(shí)現(xiàn)鸠补。
那么,既然js中已經(jīng)有處理異步事件的方法嘀掸,為何還要引入Promise這個(gè)新的方式呢紫岩?實(shí)際上,上面這段代碼只是簡單展示下回調(diào)函數(shù)的基礎(chǔ)使用睬塌,而在真正的使用場景中泉蝌,我們不得不面對各種十分復(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請求數(shù)據(jù)诅愚。在url1請求的回調(diào)中使用了foo和bar兩個(gè)函數(shù),而foo中又發(fā)送了url2劫映,url3的請求违孝。刹前。。這樣數(shù)層嵌套下來等浊,最終導(dǎo)致代碼非常的不直觀腮郊,維護(hù)起來難度也直線上升,形成常說的“回調(diào)地獄”筹燕。
了解了傳統(tǒng)上js處理異步操作的復(fù)雜和困難后轧飞,我們不禁思索,是否有方法能夠更加簡潔撒踪,直觀的去解決異步操作的種種問題过咬?答案就是我們這篇文章的主角:Promise。
2. Promise的特性及使用
在PromiseA+規(guī)范中做出了這樣定義:promise是一個(gè)包含了兼容Promise規(guī)范then方法的對象或函數(shù)制妄,與Promise最主要的交互方法是通過將函數(shù)傳入它的then方法從而獲取得Promise最終的值或Promise最終最拒絕(reject)的原因掸绞。
? 這段定義有兩個(gè)重點(diǎn):1.Promise是一個(gè)對象或函數(shù)? 2.它有一個(gè)then方法,能夠獲取prmose的最終結(jié)果耕捞。下面我們就來實(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ù)雜的場景下才能更好的發(fā)揮俺抽。我們先針對這個(gè)簡單的例子來講解下Promise的使用
首先通過 new 關(guān)鍵字實(shí)例化一個(gè)Promise對象敞映,在這個(gè)對象中傳入一個(gè)要執(zhí)行異步操作的函數(shù)。這個(gè)函數(shù)包含兩個(gè)形參:resolve和reject磷斧。這兩個(gè)形參是Promise中定義的2個(gè)函數(shù)振愿,分別在異步事件成功和失敗時(shí)調(diào)用。例3中我們在2秒后調(diào)用了resolve函數(shù)弛饭,代表著異步事件成功冕末,返回一個(gè)值。而在我們實(shí)例化Promise對象的同時(shí)侣颂,我們又調(diào)用了這個(gè)實(shí)例的then方法档桃。then方法可以說是Promise方法中的核心,它即代表著Promise約定的這層含義横蜒,在then方法中接收2個(gè)函數(shù)作為參數(shù)胳蛮,分別在異步事件成功時(shí)或失敗時(shí)執(zhí)行,并且兩個(gè)函數(shù)的參數(shù)正是異步事件成功時(shí)返回的值或失敗時(shí)原因。
其實(shí)丛晌,使用Promise對象來處理異步事件比起使用傳統(tǒng)的回調(diào)函數(shù)的一個(gè)優(yōu)點(diǎn)在于:Promise規(guī)范了處理異步事件的流程。我們不必再深入異步事件的內(nèi)部斗幼,去分析種種狀態(tài)變化后對應(yīng)的回調(diào)究竟如何調(diào)用澎蛛,也不必過多考慮異步事件內(nèi)部發(fā)生錯(cuò)誤時(shí)該如何捕獲,我們只需要在合適的時(shí)候通知Promise返回成功或失敗狀態(tài)蜕窿,剩下的事統(tǒng)統(tǒng)交給Promise去解決谋逻。
以上我們大致了解了Promise的處理流程,在詳細(xì)講解Promise對象中的方法之前有必要先了解一下Promise的狀態(tài)概念毁兆。
一個(gè)Promise對象在實(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對象都只能處于以上其中狀態(tài)的一種梅桩,當(dāng)Promise對象處于Pending狀態(tài)時(shí)壹粟,它可以轉(zhuǎn)化成Fulfilled 或Rejected 狀態(tài),而當(dāng)Promise對象處于Fulfilled 或Rejected狀態(tài)時(shí)宿百,它不能再轉(zhuǎn)化成其他狀態(tài)趁仙。
可以用一張圖來直白的表示上面這段話
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(圖片取自Promise迷你書)
在了解了Promise的三種狀態(tài)后 ,接下來可以詳細(xì)了解下Promise對象的幾個(gè)方法
resolve()
resolve方法是在一個(gè)Promise對象實(shí)例化時(shí)傳入的任務(wù)函數(shù)的第一個(gè)參數(shù)垦页,它的作用是讓Promise進(jìn)入“Fulfilled ”狀態(tài)雀费,resolve方法只接受一個(gè)參數(shù),即異步事件的返回值value外臂。
reject()
reject方法與resolve方法正好相反坐儿,它是在一個(gè)Promise對象實(shí)例化時(shí)傳入的任務(wù)函數(shù)的第二個(gè)參數(shù),它的作用是讓Promise進(jìn)入“Rejected”狀態(tài)宋光,reject方法同樣只接受一個(gè)參數(shù)貌矿,即異步事件失敗或異常的原因reason。
Promise.prototype.then()
then方法是Promise對象方法的重中之重罪佳,它是Promise實(shí)例的方法逛漫,用來注冊Promise對象成功時(shí)執(zhí)行的回調(diào)函數(shù)(onFulfilled)和失敗時(shí)執(zhí)行的回調(diào)函數(shù)(onRejected)。一個(gè)then方法的返回值仍然是一個(gè)Promsie對象赘艳。因此酌毡,then方法支持鏈?zhǔn)秸{(diào)用,也就是一個(gè)一個(gè)then方法的返回值可以繼續(xù)調(diào)用then蕾管。而相鏈接的then方法中枷踏,在上一個(gè)then方法的onFulfilled或onRejected回調(diào)函數(shù)中通過 return value(reason)的方式,把這個(gè)結(jié)果作為下一個(gè)then中的回調(diào)函數(shù)的參數(shù)被接收掰曾。onFulfilled和onRejected函數(shù)的返回值可以是任何javascript值旭蠕,甚至一個(gè)Promise對象的成功或失敗時(shí)的回調(diào)函數(shù)可以返回一個(gè)新的Promise對象。這樣的特性使得例2中那種復(fù)雜的異步事件嵌套的場景處理得以簡化。下面是使用Promise來重寫的例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注冊的onFulfilled和onRejected函數(shù)會(huì)按照注冊的順序執(zhí)行婉烟。
Promise.prototype.catch()
catch方法是一個(gè)then方法的語法糖,它只接受一個(gè)失敗處理函數(shù)onRejected暇屋,實(shí)際上等同于以下代碼:
new Promsie.then(null,function(){
? ? do something...
})
Promise.all()
all方法是Promsie對象的靜態(tài)方法似袁,使用方式是 Promise.all()。all方法接收的參數(shù)為一個(gè)包含數(shù)個(gè)Promise對象實(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í)例的順序來排列的联予。
2.當(dāng)任何一個(gè)promise失敗后啼县,all方法直接將返回的Promise對象的狀態(tài)變?yōu)镽ejected,并調(diào)用then方法的onRejected函數(shù)沸久,把失敗的原因傳遞出來季眷。
Promise.resolve()
Promsie對象本身存在一個(gè)resolve方法,它的作用是立刻返回一個(gè)狀態(tài)為Fulfilled的Promise對象實(shí)例卷胯。如果你在這個(gè)resolve方法中傳入的是一個(gè)Promise實(shí)例的話子刮,那么resolve方法會(huì)保持這個(gè)Promise實(shí)例的狀態(tài),并根據(jù)它最后返回的狀態(tài)來調(diào)用resolve方法返回的Promise實(shí)例then方法的onResolve或onRejected函數(shù)窑睁。
其實(shí)這個(gè)方法最常用的場景是講一個(gè)普通的值轉(zhuǎn)換成一個(gè)Promise實(shí)例挺峡。一般來說不是很常用。
Promise.reject()
與Promise.resolve()相反担钮,它的作用是立刻返回一個(gè)狀態(tài)為Rejected的Promise對象實(shí)例橱赠。實(shí)際上這個(gè)方法是一個(gè)語法糖,它等同于以下代碼:
new Promise(function(resolve,reject){
? ? reject(reason);
})
以上就是一個(gè)ES6中的Promise對象中所包含的常用方法箫津。
3. 一個(gè)符合PromiseA+規(guī)范的Promise對象的完整實(shí)現(xiàn)
? 想必看到這里的一些讀者會(huì)不禁思考病线,Promise對象究竟是如何實(shí)現(xiàn)的呢吓著?我個(gè)人參考了一些資料實(shí)現(xiàn)了一個(gè)符合PromiseA+規(guī)范的Promise對象鲤嫡,把源代碼貼在下面送挑,有興趣的朋友可以參考一下,實(shí)際上代碼本身并不是很多暖眼,各位看完以后可以嘗試用自己的方式再實(shí)現(xiàn)一遍惕耕。同時(shí)附上一個(gè)測試工具,里面包含了幾百個(gè)測試用例诫肠,用來測試我們自己寫的Promise是否完美的符合PromiseA+規(guī)范司澎。
使用的方法很簡單
npm i -g promises-aplus-tests
promises-aplus-tests Promise.js
安裝后運(yùn)行你的js文件就可以測試你的代碼是否符合規(guī)范了。
下面就是我實(shí)現(xiàn)的Promise對象的代碼
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)一性和注冊的回調(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對象挤安,即一個(gè)擁有then方法的對象,那么使用它的then方法去獲得它的最終返回值丧鸯。目的是為了兼容其他Promise庫
? ? 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方法注冊的時(shí)候如果Promise的狀態(tài)已經(jīng)改變,那么立即執(zhí)行對應(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('無法遍歷的類型!'));
? ? ? ? }
? ? });
? ? 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('無法遍歷的類型!'));
? ? ? ? }
? ? });
? ? 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;
//這是為了讓代碼能夠測試而開放的接口围肥,詳見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)非常正常蜂怎,不過筆者盡量使用了自己的理解去闡述Promise的相關(guān)知識穆刻。如果你發(fā)現(xiàn)本文中有哪些疏漏,歡迎發(fā)私信給我進(jìn)行斧正杠步。同時(shí)也可以在下面留言給我氢伟,我會(huì)一一查看,盡量回復(fù)幽歼。