摘要:前言中的異步,剛開(kāi)始的時(shí)候都是用回調(diào)函數(shù)實(shí)現(xiàn)的,所以如果異步嵌套的話,就有出現(xiàn)回調(diào)地獄,使得代碼難以閱讀和難以維護(hù),后來(lái)出現(xiàn)了,解決了回調(diào)地獄的問(wèn)題。
前言
js中的異步,剛開(kāi)始的時(shí)候都是用回調(diào)函數(shù)實(shí)現(xiàn)的,所以如果異步嵌套的話,就有出現(xiàn)回調(diào)地獄,使得代碼難以閱讀和難以維護(hù),后來(lái)es6出現(xiàn)了promise,解決了回調(diào)地獄的問(wèn)題。現(xiàn)在我們就自己寫(xiě)代碼實(shí)現(xiàn)一下promise,這樣才能深入理解promise的運(yùn)行機(jī)制,對(duì)以后使用promise也能夠更加得心應(yīng)手。開(kāi)始之前可以先看下promise的官網(wǎng)
promise/A+
先來(lái)看下promise的用法
</>復(fù)制代碼
new Promise((resolve,reject)=>{
resolve(1);
reject(11);
}).then(res=>{
console.log(res);
setTimeout(()=>{
return new Promise((resolve,reject)=>{
resolve(2)
})
},1000)
}).then(res2=>{
console.log(res2);
});
控制臺(tái)打印
1
...1s later
2
先分析下上面這段代碼,先提出幾個(gè)問(wèn)題
1.第一段resolve和reject都有,但是只輸出了1,為什么?
2.then里的res是如何取到resolve中的值的?
3.promise是如何做到鏈?zhǔn)秸{(diào)用的?
promise中有個(gè)狀態(tài)機(jī)的概念,先說(shuō)下為什么要有狀態(tài)機(jī)的概念呢,因?yàn)閜romise的狀態(tài)是單向變化的,有三種狀態(tài),pending,fullfilled,rejected,而這三種狀態(tài)只能從pending->fullfilled或者pending->rejected這兩種形式,也就是說(shuō)執(zhí)行了fullfilled之后,就不會(huì)執(zhí)行rejected。這就解釋了上面的第一個(gè)問(wèn)題。
下面我們來(lái)看下具體實(shí)現(xiàn)的完整代碼
</>復(fù)制代碼
const PENDING = "PENDING";
const FULLFILLED = "FULLFILLED";
const REJECTED = "REJECTED";
class Promise{
constructor(fn){
this.status = PENDING;//狀態(tài)
this.data = undefined;//返回值
this.defercb = [];//回調(diào)函數(shù)數(shù)組
//執(zhí)行promise的參數(shù)函數(shù),并把resolve和reject的this綁定到promise的this
fn(this.resolve.bind(this),this.reject.bind(this));
}
resolve(value){
if(this.status === PENDING){
//只能pending=>fullfied
this.status = FULLFILLED;
this.data = value;
this.defercb.map(item=>item.onFullFilled());
}
}
reject(value){
if(this.status === PENDING){
//只能pending=>rejected
this.status = REJECTED;
this.data = value;
this.defercb.map(item=>item.onRejected());
}
}
then(resolveThen,rejectThen){
//如果沒(méi)有resolveThen方法,保證值可以穿透到下一個(gè)then里有resolveThen的方法中
resolveThen = typeof resolveThen === "function" ? resolveThen : function(v) {return v};
rejectThen = typeof rejectThen === "function" ? rejectThen : function(r) {return r};
//返回的都是promise對(duì)象,這樣就可以保證鏈?zhǔn)秸{(diào)用了
switch(this.status){
case PENDING:
return new Promise((resolve,reject)=>{
const onFullFilled = () => {
const result = resolveThen(this.data);//這里調(diào)用外部then的resolveThen方法,將值傳回去
//如果返回值是promise對(duì)象,執(zhí)行then方法,取它的結(jié)果作為新的promise實(shí)例的結(jié)果,因?yàn)閠his.data會(huì)重新賦值
result instanceof Promise && result.then(resolve,reject);
}
const onRejected = ()=>{
const result = rejectThen(this.data);
result instanceof Promise && result.then(resolve,reject);
}
this.defercb.push({onFullFilled,onRejected});
});
break;
case FULLFILLED:
return new Promise((resolve,reject)=>{
const result = resolveThen(this.data);
result instanceof Promise && result.then(resolve,reject);
resolve(result);
})
break;
case REJECTED:
return new Promise((resolve,reject)=>{
const result = rejectThen(this.data);
result instanceof Promise && result.then(resolve,reject);
reject(result)
})
break;
}
}
}
運(yùn)行下面的例子
</>復(fù)制代碼
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
}).then((res2) => {
console.log(res2);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
}, 1000);
});
}).then((res3) => {
console.log(res3);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
}, 1000);
});
}).then((res4) => {
console.log(res4);
});
控制臺(tái)打印
...1s later
1
...1s later
2
...1s later
3
說(shuō)明上面的實(shí)現(xiàn)是沒(méi)有問(wèn)題的
不過(guò)還有一個(gè)問(wèn)題,就是事件循環(huán)的順序問(wèn)題,比如執(zhí)行下面的代碼
</>復(fù)制代碼
new Promise((resolve) => {
resolve();
})
.then(() => {
console.log("1");
})
.then(() => {
console.log("2");
});
console.log("3");
并沒(méi)有像預(yù)想中輸出3,1,2,而是輸出了1,2,3,原因就是因?yàn)槲覀兊倪@個(gè)Promise是在主線程中,沒(méi)有在下一個(gè)任務(wù)隊(duì)列中,可以加上settimeout解決這個(gè)問(wèn)題,不過(guò)這也只是為了讓我們更好理解執(zhí)行順序而已,然而實(shí)際上是promise是屬于微任務(wù)中的,而settimeout是屬于宏任務(wù),還是不太一樣的
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/99315.html
摘要:有一個(gè)和相關(guān)的更大的問(wèn)題。最后,請(qǐng)負(fù)有責(zé)任感并且使用安全的擴(kuò)展。深入理解五部曲異步問(wèn)題深入理解五部曲轉(zhuǎn)換問(wèn)題深入理解五部曲可靠性問(wèn)題深入理解五部曲擴(kuò)展性問(wèn)題深入理解五部曲樂(lè)高問(wèn)題最后,安利下我的個(gè)人博客,歡迎訪問(wèn) 原文地址:http://blog.getify.com/promis... 現(xiàn)在,我希望你已經(jīng)看過(guò)深入理解Promise的前三篇文章了。并且假設(shè)你已經(jīng)完全理解Promises...
摘要:的翻譯文檔由的維護(hù)很多人說(shuō),阮老師已經(jīng)有一本關(guān)于的書(shū)了入門(mén),覺(jué)得看看這本書(shū)就足夠了。前端的異步解決方案之和異步編程模式在前端開(kāi)發(fā)過(guò)程中,顯得越來(lái)越重要。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(shū)(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書(shū)的目的是以目前還在制定中的ECMASc...
摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。寫(xiě)一個(gè)符合規(guī)范并可配合使用的寫(xiě)一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來(lái)處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問(wèn)題描述 在開(kāi)發(fā)過(guò)程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過(guò)http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過(guò)...
摘要:簡(jiǎn)單的說(shuō),即將到來(lái)的標(biāo)準(zhǔn)指出是一個(gè),所以作為一個(gè),必須可以被子類(lèi)化。保護(hù)還是子類(lèi)化這是個(gè)問(wèn)題我真的希望我能創(chuàng)建一個(gè)忠實(shí)的給及以下。 原文地址:http://blog.getify.com/promis... 如果你需要趕上我們關(guān)于Promise的進(jìn)度,可以看看這個(gè)系列前兩篇文章深入理解Promise五部曲--1.異步問(wèn)題和深入理解Promise五部曲--2.控制權(quán)轉(zhuǎn)移問(wèn)題。 Promi...
摘要:雖然在后面,但是我先執(zhí)行繼續(xù)看控制臺(tái)原來(lái)函數(shù)返回的是一個(gè)對(duì)象,如果要獲取到返回值,我們應(yīng)該用方法,繼續(xù)修改代碼。這就是來(lái)處理異步。 目前async/await 已經(jīng)被標(biāo)準(zhǔn)化,我們需要盡快將學(xué)習(xí)進(jìn)程提上日程。先說(shuō)一下async的用法,它作為一個(gè)關(guān)鍵字放到函數(shù)前面,用于表示函數(shù)是一個(gè)異步函數(shù),因?yàn)閍sync就是異步的意思,異步函數(shù)也就意味著該函數(shù)的執(zhí)行不會(huì)阻塞后面代碼的執(zhí)行。下面寫(xiě)一個(gè)as...
閱讀 617·2021-11-15 11:38
閱讀 1251·2021-10-11 10:59
閱讀 3524·2021-09-07 09:58
閱讀 515·2019-08-30 15:44
閱讀 3543·2019-08-28 18:14
閱讀 2629·2019-08-26 13:32
閱讀 3538·2019-08-26 12:23
閱讀 2441·2019-08-26 10:59