摘要:上代碼異步執(zhí)行成功的構(gòu)造函數(shù)接收一個(gè)函數(shù)參數(shù),并傳入兩個(gè)參數(shù),分別表示異步操作執(zhí)行成功后的回調(diào)函數(shù)和異步操作執(zhí)行失敗后的回調(diào)函數(shù)。第一個(gè)回調(diào)函數(shù)是對象的狀態(tài)變?yōu)闀r(shí)調(diào)用,第二個(gè)回調(diào)函數(shù)是對象的狀態(tài)變?yōu)闀r(shí)調(diào)用。
這篇文章只解決三個(gè)問題。
什么是promise?
promise有什么用?
promise怎么用?
1.什么是promise?
對于ES6來說,就是一個(gè)構(gòu)造函數(shù),可以用new Promise( )來創(chuàng)建Promise實(shí)例。
2.promise有什么用?
先想象兩個(gè)場景:
一,業(yè)務(wù)中,需要請求后臺(tái)的兩個(gè)接口,但是需要第一個(gè)返回成功結(jié)果之后再請求第二個(gè)接口,這是可能會(huì)寫成下面這個(gè)樣子,
var request = function(){ var xhr1 = new XMLHttpRequest(); xhr1.onreadystatechange = function(){ if(xhr1.readyState !== 4){ alert("第一步請求失敗了,請重試!"); return; } if(xhr1.status === 200){ console.log("第一步請求成功了,我們開始下一步吧!"); var xhr2 = new XMLHttpRequest(); xhr2.open("GET", url); xhr2.onreadystatechange = function(){ if(xhr2.readyState !== 4){ alert("第二步請求失敗了,請重試!"); return; } if(xhr2.status === 200){ //兩次請求成功后做的一些事情.... } else { alert("第二步請求失敗了,請重試!"); } }; xhr2.responseType = "json"; xhr2.setRequestHeader("Accept", "application/json2"); xhr2.send(); } else { alert("第一步請求失敗了,請重試!"); } }; xhr1.responseType = "json"; xhr1.setRequestHeader("Accept", "application/json1"); xhr1.send(); }); } request();
上面代碼用xhr對象實(shí)現(xiàn)了兩次異步請求,代碼很長。不過這僅僅是兩層回調(diào)嵌套,想象一下更多的異步回調(diào)依賴有多可怕…
二,我們都知道,nodejs的一大特點(diǎn)就是事件驅(qū)動(dòng),那就肯定要利用事件的回調(diào)函數(shù)來處理邏輯,多層的回調(diào)嵌套也就在所難免。那么你的代碼很可能就會(huì)寫成這個(gè)德行,
async(1,function(value){ async(value,function(value){ async(value,function(value){ async(value,function(value){ async(value,function(value){ async(value,function(value){ async(value,function(value){ async(value,function(value){ async(value,final); }); }); }); }); }); }); }); })
就此你掉進(jìn)了又長又丑的嵌套地獄。
咋辦?
用promise(回答了“promise是干啥的”)。
咋用?
往下看。
3.promise 怎么用?
在學(xué)習(xí)怎么使用Promise的同時(shí),需要不時(shí)接觸幾個(gè)關(guān)于它的知識(shí)點(diǎn)。能理解最好,理解不了用著用著就理解了。
首先需要了解的是每個(gè)Promise實(shí)例都有三種狀態(tài):
1.進(jìn)行中狀態(tài) pending
2.成功狀態(tài) resolved
3.失敗狀態(tài) rejected
同一時(shí)間下Promise實(shí)例只能有一種狀態(tài),且只能改變一次,改完之后就再也不能變了。
變化的途徑只有兩種,第一,從pending變?yōu)閞esolved;第二,從pending變?yōu)閞ejected。
接下來就一步步的完成一個(gè)promise的使用。
第一步,new一個(gè)Promise實(shí)例。上代碼:
var promise = new Promise(function(resolve,reject){ if(/*異步執(zhí)行成功*/){ resolve(value) } else { reject(error) } });
Promise的構(gòu)造函數(shù)接收一個(gè)函數(shù)參數(shù),并傳入兩個(gè)參數(shù)resolve,reject分別表示異步操作執(zhí)行成功后的回調(diào)函數(shù)和異步操作執(zhí)行失敗后的回調(diào)函數(shù)。執(zhí)行resolve(),會(huì)將當(dāng)前promise對象的狀態(tài)更改為resolved,執(zhí)行reject()會(huì)將當(dāng)前promise對象的狀態(tài)更改為rejected。
這時(shí)一個(gè)Promise對象已經(jīng)創(chuàng)建完成,異步腳本的結(jié)果也已經(jīng)被存在這個(gè)Promise對象中了,但它是成功是失???我們怎么讀取呢?
第二步,then方法。接著上代碼:
var promise = new Promise(function(resolve,reject){ if(/*異步執(zhí)行成功*/){ resolve(value); } else { reject(error); } }); promise.then(function(value){ console.log(value); },function(error){ console.log(error); })
每個(gè)Promise實(shí)例都有一個(gè)then方法,它就是處理Promise中存儲(chǔ)的異步執(zhí)行結(jié)果的方法。then方法可以接受兩個(gè)回調(diào)函數(shù)作為參數(shù)。第一個(gè)回調(diào)函數(shù)是Promise對象的狀態(tài)變?yōu)镽esolved時(shí)調(diào)用,第二個(gè)回調(diào)函數(shù)是Promise對象的狀態(tài)變?yōu)镽eject時(shí)調(diào)用。其中,第二個(gè)函數(shù)是可選的,不一定要提供。這兩個(gè)函數(shù)都接受Promise對象傳出的值作為參數(shù)。
需要特別注意的是then方法的返回值還是一個(gè)Promise!這就意味著then方法是支持鏈?zhǔn)秸{(diào)用的。
第三步,catch方法。
catch方法等同于then(null,function(){}),也就是用來處理rejected狀態(tài)下Promise數(shù)據(jù)的。關(guān)于catch個(gè)人認(rèn)為記住兩點(diǎn)就好。第一,用catch來處理rejected的Promise;第二,用catch來捕獲之前所有鏈?zhǔn)秸{(diào)用中拋出的Error對象,注意是所有,包括Promise構(gòu)造函數(shù)、then方法、鏈?zhǔn)秸{(diào)用的then方法、以及之前的catch,這些步驟拋出的錯(cuò)誤都可以被catch捕獲。
var promise = new Promise(function(resolve,reject){ if(false){ resolve(value); } else { reject(error); } }); promise .then(function(value){ console.log(value); }) .catch(function(reason){ console.log(error); })
上面代碼會(huì)輸出reject(error)傳入的error值,也就是catch的第一種用法。
var promise = new Promise(function(resolve,reject){ if(true){ resolve(value); } else { reject(error); } }); promise .then(function(value){ console.log(value); console.log(x); }) .catch(function(reason){ console.log(reason); })
上面代碼會(huì)將Promise的狀態(tài)改為resolved,并執(zhí)行then方法,在then方法中會(huì)拋出一個(gè)x變量未定義的錯(cuò)誤,并由catch方法捕獲到并打印出來,這就是catch的第二個(gè)用法。
至此實(shí)際上我們已經(jīng)學(xué)會(huì)了Promise的基礎(chǔ)應(yīng)用。接下來再學(xué)習(xí)兩個(gè)比較好用的方法。
第一個(gè),Promise.all方法。
該方法能夠并行運(yùn)行異步方法,并在結(jié)果都返回之后進(jìn)行統(tǒng)一處理,并返回一個(gè)新的Promise對象。
var p = Promise.all([p1, p2, p3]);
上面代碼中,Promise.all方法接受一個(gè)“數(shù)組”作為參數(shù),p1、p2、p3都是Promise對象的實(shí)例。
p的狀態(tài)由p1、p2、p3決定,分成兩種情況。
(1)只有p1、p2、p3的狀態(tài)都變成fulfilled,p的狀態(tài)才會(huì)變成fulfilled,此時(shí)p1、p2、p3的返回值組成一個(gè)數(shù)組,傳遞給p的回調(diào)函數(shù)。(fulfilled可以理解為resolved)
(2)只要p1、p2、p3之中有一個(gè)被rejected,p的狀態(tài)就變成rejected,此時(shí)第一個(gè)被reject的實(shí)例的返回值,會(huì)傳遞給p的回調(diào)函數(shù)。
var p = Promise.all([p1,p2,p3]); p.then(function(results){ console.log(results) });
當(dāng)打開網(wǎng)頁時(shí),需要預(yù)先加載各種資源如圖片、flash以及各種靜態(tài)文件,所有的都加載完后,我們再進(jìn)行頁面的初始化。這種場景是很適合使用Promise.all的。
第二個(gè),Promise.race方法。
與all方法類似,同樣是能夠并行運(yùn)行異步方法,并在結(jié)果都返回之后進(jìn)行統(tǒng)一處理,并返回一個(gè)新的Promise對象。
var p = Promise.race([p1,p2,p3]);
上面代碼中,只要p1、p2、p3之中有一個(gè)實(shí)例率先改變狀態(tài),p的狀態(tài)就跟著改變。那個(gè)率先改變的 Promise 實(shí)例的返回值,就傳遞給p的回調(diào)函數(shù),也就是說誰執(zhí)行的快就返回誰的。
race方法可以添加請求超時(shí)的限制。
//請求某個(gè)圖片資源 function requestImg(){ var p = new Promise(function(resolve, reject){ var img = new Image(); img.onload = function(){ resolve(img); } img.src = "xxxxxx"; }); return p; } //延時(shí)函數(shù),用于給請求計(jì)時(shí) function timeout(){ var p = new Promise(function(resolve, reject){ setTimeout(function(){ reject("圖片請求超時(shí)"); }, 5000); }); return p; } Promise .race([requestImg(), timeout()]) .then(function(results){ console.log(results); }) .catch(function(reason){ console.log(reason); });
到這,關(guān)于Promise的三個(gè)問題已經(jīng)解答完了,希望能夠?yàn)榇蠹覍W(xué)習(xí)Promise提供一點(diǎn)幫助。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/82256.html
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。異步編程入門的全稱是前端經(jīng)典面試題從輸入到頁面加載發(fā)生了什么這是一篇開發(fā)的科普類文章,涉及到優(yōu)化等多個(gè)方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識(shí)之 HTTP 協(xié)議 詳細(xì)介紹 HTT...
摘要:意味著操作成功完成。當(dāng)調(diào)用方法的時(shí)候會(huì)設(shè)置一個(gè)狀態(tài),調(diào)用方法的時(shí)候會(huì)設(shè)置一個(gè)狀態(tài)。返回是自定義的,狀態(tài)由自己設(shè)但不能不給狀態(tài),不然不會(huì)執(zhí)行下一個(gè)鏈詳細(xì)文檔文檔 背景:在一個(gè)方法中處理一個(gè)復(fù)雜的異步操作時(shí)會(huì)涉及到多個(gè)異步處理,它們可能是層層嵌套導(dǎo)致這個(gè)方法異常的龐大,影響日后的代碼維護(hù)和問題的查找 解決:在ES6中提供了一個(gè)Promise的對象,它以一種鏈?zhǔn)降膶懛▽惒讲僮鬟壿嬇c異步返...
摘要:首先是一個(gè)構(gòu)造器函數(shù),使用它必須通過一個(gè)實(shí)例出來,并且出來的實(shí)例暈有一個(gè)內(nèi)置的參數(shù),這個(gè)參數(shù)是一個(gè)函數(shù),這個(gè)參數(shù)擁有自己內(nèi)置的兩個(gè)參數(shù),和,并且這兩個(gè)參數(shù)也是兩個(gè)函數(shù)異步操作成功上面這個(gè)就是一個(gè)最簡單的對象屬于的一個(gè)方法,里面的兩個(gè)參數(shù)屬于 首先promise是一個(gè)構(gòu)造器函數(shù),使用它必須通過new一個(gè)實(shí)例出來,并且new出來的實(shí)例暈有一個(gè)內(nèi)置的參數(shù),這個(gè)參數(shù)是一個(gè)函數(shù),這個(gè)參數(shù)擁有自己...
摘要:首先是一個(gè)構(gòu)造器函數(shù),使用它必須通過一個(gè)實(shí)例出來,并且出來的實(shí)例暈有一個(gè)內(nèi)置的參數(shù),這個(gè)參數(shù)是一個(gè)函數(shù),這個(gè)參數(shù)擁有自己內(nèi)置的兩個(gè)參數(shù),和,并且這兩個(gè)參數(shù)也是兩個(gè)函數(shù)異步操作成功上面這個(gè)就是一個(gè)最簡單的對象屬于的一個(gè)方法,里面的兩個(gè)參數(shù)屬于 首先promise是一個(gè)構(gòu)造器函數(shù),使用它必須通過new一個(gè)實(shí)例出來,并且new出來的實(shí)例暈有一個(gè)內(nèi)置的參數(shù),這個(gè)參數(shù)是一個(gè)函數(shù),這個(gè)參數(shù)擁有自己...
摘要:源碼學(xué)習(xí)本篇為上一篇源碼學(xué)習(xí)的補(bǔ)充,主要是來介紹和方法。那個(gè)率先改變的實(shí)例的返回值,就傳遞給的回調(diào)函數(shù)。基本介紹可見阮一峰老師的書籍。的狀態(tài)由決定,分成兩種情況。只有的狀態(tài)都變成,的狀態(tài)才會(huì)變成,此時(shí)的返回值組成一個(gè)數(shù)組,傳遞給的回調(diào)函數(shù)。 Promise源碼學(xué)習(xí)(2) 本篇為上一篇源碼學(xué)習(xí)(1)的補(bǔ)充,主要是來介紹Promise.all()和Promise.race()方法。閑話少敘...
閱讀 1711·2021-11-23 09:51
閱讀 3265·2021-09-26 10:21
閱讀 828·2021-09-09 09:32
閱讀 911·2019-08-29 16:06
閱讀 3354·2019-08-26 13:36
閱讀 810·2019-08-26 10:56
閱讀 2593·2019-08-26 10:44
閱讀 1171·2019-08-23 14:04