關(guān)于javascript中的promise的用法和注意事項(xiàng)(推薦)
一、promise描述
promise是javascript中標(biāo)準(zhǔn)的內(nèi)置對(duì)象,用于表示一個(gè)異步操作的最終狀態(tài)(是失敗還是成功完成)及其結(jié)果值。它讓你能夠把異步操作最終成功或者失敗的原因和響應(yīng)的處理程序相關(guān)聯(lián),也就是說(shuō)通過(guò)promise你可以自定義異步操作結(jié)束后該做什么。這樣的話異步方法就和同步方法很類似,也有返回值,只不過(guò)這個(gè)返回值不是立即返回最終的值,而是返回一個(gè)promise,當(dāng)promise的狀態(tài)發(fā)生改變時(shí),就會(huì)觸發(fā)相應(yīng)的處理程序。
一個(gè)promise無(wú)論什么時(shí)候都必然處于以下幾種狀態(tài):1、待定(pending) 2、已兌現(xiàn)(fulfilled) 3、已拒絕(rejected)
promise創(chuàng)建之初是待定狀態(tài),它既咩有被兌現(xiàn)也咩有被拒絕,它用于包裝還沒(méi)有被添加promise支持的函數(shù),包裝后的函數(shù)變成異步操作函數(shù),當(dāng)操作結(jié)束時(shí),會(huì)有兩個(gè)兩個(gè)分支,一個(gè)是已兌現(xiàn),一個(gè)是已拒絕,如下圖。已兌現(xiàn)狀態(tài)的promise會(huì)調(diào)用后續(xù)的then方法,而已拒絕狀態(tài)的promise既可以調(diào)用then方法,也可以被catch方法捕捉到。為什么then方法可以捕捉兩個(gè)狀態(tài)的promise呢?這里先不講,下面再詳細(xì)介紹。
二、promise 的流程走向
上圖是promise的流程圖,從左到右可以得知一個(gè)promise在待定狀態(tài)時(shí)通過(guò)兩個(gè)分支走向分別進(jìn)入then方法或者catch方法,這兩個(gè)c方法都會(huì)返回promise,如果這個(gè)promise也被敲定了,而且其后也有then方法或者catch方法,則又會(huì)進(jìn)入后續(xù)的then和catch中,直至咪有。
也就是說(shuō),promise和then或者catch可以形成一個(gè)異步操作的鏈?zhǔn)浇Y(jié)構(gòu),結(jié)合js的事件循環(huán)機(jī)制,這使得js的優(yōu)勢(shì)更加明顯,發(fā)展至今仍能在瀏覽器上頻繁看到它的身影。
我們要注意流程的特點(diǎn):
1、promise是對(duì)象,它的轉(zhuǎn)移成功不取決于返回值,而取決于狀態(tài)的敲定(是成功還是失?。?/p>
2、then和catch是函數(shù),只要有promise狀態(tài)發(fā)生了改變,該promise對(duì)應(yīng)后面的then或者catch方法就會(huì)被調(diào)用,而這兩個(gè)方法本身會(huì)返回一個(gè)promise,這個(gè)返回的promise又會(huì)影響這兩個(gè)方法后面的then或者catch方法。兩個(gè)方法的返回值一定是promise。
三、promise的創(chuàng)建
Promise
對(duì)象是由關(guān)鍵字new
及其構(gòu)造函數(shù)來(lái)創(chuàng)建的。該構(gòu)造函數(shù)會(huì)把一個(gè)叫做“處理器函數(shù)”(executor function)的函數(shù)作為它的參數(shù)。這個(gè)“處理器函數(shù)”接受兩個(gè)函數(shù)——resolve
和reject
——作為其參數(shù)。當(dāng)異步任務(wù)順利完成且返回結(jié)果值時(shí),會(huì)調(diào)用resolve
函數(shù);而當(dāng)異步任務(wù)失敗且返回失敗原因(通常是一個(gè)錯(cuò)誤對(duì)象)時(shí),會(huì)調(diào)用reject
函數(shù)。示例如下:
let myFirstPromise = new Promise(function(resolve, reject){ //當(dāng)異步代碼執(zhí)行成功時(shí),我們才會(huì)調(diào)用resolve(...), 當(dāng)異步代碼失敗時(shí)就會(huì)調(diào)用reject(...) //在本例中,我們使用setTimeout(...)來(lái)模擬異步代碼,實(shí)際編碼時(shí)可能是XHR請(qǐng)求或是HTML5的一些API方法. setTimeout(function(){ resolve("成功!"); //代碼正常執(zhí)行! }, 250); }); myFirstPromise.then(function(successMessage){ //successMessage的值是上面調(diào)用resolve(...)方法傳入的值. //successMessage參數(shù)不一定非要是字符串類型,這里只是舉個(gè)例子 console.log("Yay! " + successMessage); });
四、promise的優(yōu)勢(shì)
在promise未出現(xiàn)時(shí),如果我們調(diào)用異步代碼塊的話是沒(méi)有辦法保持順序的,而如果又出現(xiàn)了異步代碼結(jié)果之間按序的需求,該如何實(shí)現(xiàn)呢?
以前的話通常都會(huì)將異步代碼一層一層地內(nèi)嵌來(lái)實(shí)現(xiàn)異步代碼按序?qū)崿F(xiàn),但是這就造成了代碼維護(hù)困難,開(kāi)發(fā)難度增大
doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log('Got the final result: ' + finalResult); }, failureCallback); }, failureCallback); }, failureCallback);
這就是經(jīng)典的回調(diào)地獄。而如果使用了前面介紹的promise,那么代碼就變成了容易維護(hù)的鏈?zhǔn)浇Y(jié)構(gòu)
五、then方法返回的promise類型
當(dāng)一個(gè)Promise
完成(fulfilled)或者失?。╮ejected)時(shí),返回函數(shù)將被異步調(diào)用(由當(dāng)前的線程循環(huán)來(lái)調(diào)度完成)。具體的返回值依據(jù)以下規(guī)則返回。如果then
中的回調(diào)函數(shù):
- 返回了一個(gè)值,那么
then
返回的 Promise 將會(huì)成為接受狀態(tài),并且將返回的值作為接受狀態(tài)的回調(diào)函數(shù)的參數(shù)值。 - 沒(méi)有返回任何值,那么
then
返回的 Promise 將會(huì)成為接受狀態(tài),并且該接受狀態(tài)的回調(diào)函數(shù)的參數(shù)值為undefined
。 - 拋出一個(gè)錯(cuò)誤,那么
then
返回的 Promise 將會(huì)成為拒絕狀態(tài),并且將拋出的錯(cuò)誤作為拒絕狀態(tài)的回調(diào)函數(shù)的參數(shù)值。 - 返回一個(gè)已經(jīng)是接受狀態(tài)的 Promise,那么
then
返回的 Promise 也會(huì)成為接受狀態(tài),并且將那個(gè) Promise 的接受狀態(tài)的回調(diào)函數(shù)的參數(shù)值作為該被返回的Promise的接受狀態(tài)回調(diào)函數(shù)的參數(shù)值。 - 返回一個(gè)已經(jīng)是拒絕狀態(tài)的 Promise,那么
then
返回的 Promise 也會(huì)成為拒絕狀態(tài),并且將那個(gè) Promise 的拒絕狀態(tài)的回調(diào)函數(shù)的參數(shù)值作為該被返回的Promise的拒絕狀態(tài)回調(diào)函數(shù)的參數(shù)值。 - 返回一個(gè)未定狀態(tài)(
pending
)的 Promise,那么then
返回 Promise 的狀態(tài)也是未定的,并且它的終態(tài)與那個(gè) Promise 的終態(tài)相同;同時(shí),它變?yōu)榻K態(tài)時(shí)調(diào)用的回調(diào)函數(shù)參數(shù)與那個(gè) Promise 變?yōu)榻K態(tài)時(shí)的回調(diào)函數(shù)的參數(shù)是相同的。
六、catch捕捉的錯(cuò)誤
catch能捕捉promise組合中出現(xiàn)的錯(cuò)誤,但是有兩種錯(cuò)誤不能捕捉:
1、已決議的錯(cuò)誤不能捕捉
//創(chuàng)建一個(gè)新的 Promise ,且已決議 var p1 = Promise.resolve("calling next"); var p2 = p1.catch(function (reason) { //這個(gè)方法永遠(yuǎn)不會(huì)調(diào)用 console.log("catch p1!"); console.log(reason); }); p2.then(function (value) { console.log("next promise's onFulfilled"); /* next promise's onFulfilled */ console.log(value); /* calling next */ }, function (reason) { console.log("next promise's onRejected"); console.log(reason); });
2、異步函數(shù)中拋出的錯(cuò)誤不能捕捉
需要注意的是,作者親手實(shí)踐發(fā)現(xiàn):promise包裹的異步函數(shù)執(zhí)行成功后必須顯式地調(diào)用resolve和reject方法才能觸發(fā)后續(xù)then和catch方法,如果promise方法包裹的不是異步函數(shù),是普通的同步函數(shù),如果該同步代碼運(yùn)行出錯(cuò),即便沒(méi)有調(diào)用reject方法時(shí),后面的catch方法仍然能夠捕捉到這個(gè)錯(cuò)誤,但如果同步代碼沒(méi)有出錯(cuò),沒(méi)有顯式調(diào)用resolve方法轉(zhuǎn)移的話,后續(xù)的then方法不會(huì)觸發(fā)。
七、高級(jí)示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 10px; } html{ width: 100%; height: 100%; } body{ width: 100%; height: 100%; display:flex; align-items: center; justify-content: center; } div.displaydatabox{ width: 300px; height: 300px; border-radius: 50px; text-align: center; line-height: 300px; box-shadow: 0 0 10px 2px black; } div.button{ width: 100px; height: 50px; border-radius: 21px; border: 2px solid orange; line-height: 50px; text-align: center; cursor: pointer; } </style> </head> <body> <div class="button">創(chuàng)建</div> <div class="button">輸入文字</div> <div class="button">消失</div> <script lang="javascript"> let buttonlist=document.querySelectorAll("div.button"); let body=document.querySelector("body"); buttonlist[0].onclick=function() { let div=document.createElement("div"); div.className="displaydatabox"; body.appendChild(div); } buttonlist[2].onclick=function() { let div=document.querySelector("div.displaydatabox"); body.removeChild(div); } buttonlist[1].onclick=function(e) { let p1=new Promise((resolve,reject)=> { setTimeout(()=>{//用setTimeout函數(shù)模擬異步函數(shù) let div=document.querySelector("div.displaydatabox"); div.textContent="這是promise實(shí)驗(yàn)"; //reject(1); resolve(1);//調(diào)用resolve將調(diào)用第一個(gè)then },2000); }).then(function(resolve){ return new Promise((resolve,reject)=>{ console.log("這是狀態(tài)咩有敲定的promise,所以不會(huì)調(diào)用后面所有的then方法"); //resolve(1)//沒(méi)有調(diào)用resolve或者reject,所以狀態(tài)未敲定。如果調(diào)用,將輸出1和finally it has been called!! }) .then(function(e){ console.log(e); }); }).catch(function(e) { console.log(e+" 沒(méi)有塊可以輸入!!"); }).then(()=> { console.log("finally it has been called!!"); }) } </script> </body> </html>
到此這篇關(guān)于關(guān)于javascript中的promise的用法和注意事項(xiàng)的文章就介紹到這了,更多相關(guān)js中promise用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
uni-app彈出層uni-popup使用及修改默認(rèn)樣式的方法實(shí)例
我們?cè)谑褂胾niapp開(kāi)發(fā)的時(shí)候,有時(shí)可以使用uniapp自有的樣式模板,這樣可以提高開(kāi)發(fā)效率,下面這篇文章主要給大家介紹了關(guān)于uni-app彈出層uni-popup使用及修改默認(rèn)樣式的相關(guān)資料,需要的朋友可以參考下2022-11-11微信小程序開(kāi)發(fā)之從相冊(cè)獲取圖片 使用相機(jī)拍照 本地圖片上傳
本篇文章主要介紹了微信小程序開(kāi)發(fā)之從相冊(cè)獲取圖片--使用相機(jī)拍照,本地圖片上傳的相關(guān)資料。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-04-04微信小程序?qū)崿F(xiàn)天氣預(yù)報(bào)功能(附源碼)
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)天氣預(yù)報(bào)功能(附源碼),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12OpenLayer3自定義測(cè)量控件MeasureTool
這篇文章主要為大家詳細(xì)介紹了OpenLayer3自定義測(cè)量控件MeasureTool,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09JavaScript動(dòng)態(tài)生成帶刪除行功能的表格
這篇文章主要為大家詳細(xì)介紹了JavaScript動(dòng)態(tài)生成帶刪除行功能的表格,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09javascript中for/in循環(huán)及使用技巧
如果您希望一遍又一遍地運(yùn)行相同的代碼,并且每次的值都不同,那么使用循環(huán)是很方便的,本篇文章給大家介紹javascript中for/in循環(huán)及使用技巧 ,需要的朋友可以參考下2015-09-09