一、promise描述
promise是javascript中標準的內(nèi)置對象,用于表示一個異步操作的最終狀態(tài)(是失敗還是成功完成)及其結(jié)果值。它讓你能夠把異步操作最終成功或者失敗的原因和響應的處理程序相關聯(lián),也就是說通過promise你可以自定義異步操作結(jié)束后該做什么。這樣的話異步方法就和同步方法很類似,也有返回值,只不過這個返回值不是立即返回最終的值,而是返回一個promise,當promise的狀態(tài)發(fā)生改變時,就會觸發(fā)相應的處理程序。
一個promise無論什么時候都必然處于以下幾種狀態(tài):1、待定(pending) 2、已兌現(xiàn)(fulfilled) 3、已拒絕(rejected)
promise創(chuàng)建之初是待定狀態(tài),它既咩有被兌現(xiàn)也咩有被拒絕,它用于包裝還沒有被添加promise支持的函數(shù),包裝后的函數(shù)變成異步操作函數(shù),當操作結(jié)束時,會有兩個兩個分支,一個是已兌現(xiàn),一個是已拒絕,如下圖。已兌現(xiàn)狀態(tài)的promise會調(diào)用后續(xù)的then方法,而已拒絕狀態(tài)的promise既可以調(diào)用then方法,也可以被catch方法捕捉到。為什么then方法可以捕捉兩個狀態(tài)的promise呢?這里先不講,下面再詳細介紹。
二、promise 的流程走向
上圖是promise的流程圖,從左到右可以得知一個promise在待定狀態(tài)時通過兩個分支走向分別進入then方法或者catch方法,這兩個c方法都會返回promise,如果這個promise也被敲定了,而且其后也有then方法或者catch方法,則又會進入后續(xù)的then和catch中,直至咪有。
也就是說,promise和then或者catch可以形成一個異步操作的鏈式結(jié)構(gòu),結(jié)合js的事件循環(huán)機制,這使得js的優(yōu)勢更加明顯,發(fā)展至今仍能在瀏覽器上頻繁看到它的身影。
我們要注意流程的特點:
1、promise是對象,它的轉(zhuǎn)移成功不取決于返回值,而取決于狀態(tài)的敲定(是成功還是失敗)
2、then和catch是函數(shù),只要有promise狀態(tài)發(fā)生了改變,該promise對應后面的then或者catch方法就會被調(diào)用,而這兩個方法本身會返回一個promise,這個返回的promise又會影響這兩個方法后面的then或者catch方法。兩個方法的返回值一定是promise。
三、promise的創(chuàng)建
Promise
對象是由關鍵字new
及其構(gòu)造函數(shù)來創(chuàng)建的。該構(gòu)造函數(shù)會把一個叫做“處理器函數(shù)”(executor function)的函數(shù)作為它的參數(shù)。這個“處理器函數(shù)”接受兩個函數(shù)——resolve
和reject
——作為其參數(shù)。當異步任務順利完成且返回結(jié)果值時,會調(diào)用resolve
函數(shù);而當異步任務失敗且返回失敗原因(通常是一個錯誤對象)時,會調(diào)用reject
函數(shù)。示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
let myFirstPromise = new Promise( function (resolve, reject){ //當異步代碼執(zhí)行成功時,我們才會調(diào)用resolve(...), 當異步代碼失敗時就會調(diào)用reject(...) //在本例中,我們使用setTimeout(...)來模擬異步代碼,實際編碼時可能是XHR請求或是HTML5的一些API方法. setTimeout( function (){ resolve( "成功!" ); //代碼正常執(zhí)行! }, 250); }); myFirstPromise.then( function (successMessage){ //successMessage的值是上面調(diào)用resolve(...)方法傳入的值. //successMessage參數(shù)不一定非要是字符串類型,這里只是舉個例子 console.log( "Yay! " + successMessage); }); |
四、promise的優(yōu)勢
在promise未出現(xiàn)時,如果我們調(diào)用異步代碼塊的話是沒有辦法保持順序的,而如果又出現(xiàn)了異步代碼結(jié)果之間按序的需求,該如何實現(xiàn)呢?
以前的話通常都會將異步代碼一層一層地內(nèi)嵌來實現(xiàn)異步代碼按序?qū)崿F(xiàn),但是這就造成了代碼維護困難,開發(fā)難度增大
1
2
3
4
5
6
7
|
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,那么代碼就變成了容易維護的鏈式結(jié)構(gòu)
五、then方法返回的promise類型
當一個Promise
完成(fulfilled)或者失敗(rejected)時,返回函數(shù)將被異步調(diào)用(由當前的線程循環(huán)來調(diào)度完成)。具體的返回值依據(jù)以下規(guī)則返回。如果then
中的回調(diào)函數(shù):
-
返回了一個值,那么
then
返回的 Promise 將會成為接受狀態(tài),并且將返回的值作為接受狀態(tài)的回調(diào)函數(shù)的參數(shù)值。 -
沒有返回任何值,那么
then
返回的 Promise 將會成為接受狀態(tài),并且該接受狀態(tài)的回調(diào)函數(shù)的參數(shù)值為undefined
。 -
拋出一個錯誤,那么
then
返回的 Promise 將會成為拒絕狀態(tài),并且將拋出的錯誤作為拒絕狀態(tài)的回調(diào)函數(shù)的參數(shù)值。 -
返回一個已經(jīng)是接受狀態(tài)的 Promise,那么
then
返回的 Promise 也會成為接受狀態(tài),并且將那個 Promise 的接受狀態(tài)的回調(diào)函數(shù)的參數(shù)值作為該被返回的Promise的接受狀態(tài)回調(diào)函數(shù)的參數(shù)值。 -
返回一個已經(jīng)是拒絕狀態(tài)的 Promise,那么
then
返回的 Promise 也會成為拒絕狀態(tài),并且將那個 Promise 的拒絕狀態(tài)的回調(diào)函數(shù)的參數(shù)值作為該被返回的Promise的拒絕狀態(tài)回調(diào)函數(shù)的參數(shù)值。 -
返回一個未定狀態(tài)(
pending
)的 Promise,那么then
返回 Promise 的狀態(tài)也是未定的,并且它的終態(tài)與那個 Promise 的終態(tài)相同;同時,它變?yōu)榻K態(tài)時調(diào)用的回調(diào)函數(shù)參數(shù)與那個 Promise 變?yōu)榻K態(tài)時的回調(diào)函數(shù)的參數(shù)是相同的。
六、catch捕捉的錯誤
catch能捕捉promise組合中出現(xiàn)的錯誤,但是有兩種錯誤不能捕捉:
1、已決議的錯誤不能捕捉
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
//創(chuàng)建一個新的 Promise ,且已決議 var p1 = Promise.resolve( "calling next" ); var p2 = p1. catch ( function (reason) { //這個方法永遠不會調(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ù)中拋出的錯誤不能捕捉
需要注意的是,作者親手實踐發(fā)現(xiàn):promise包裹的異步函數(shù)執(zhí)行成功后必須顯式地調(diào)用resolve和reject方法才能觸發(fā)后續(xù)then和catch方法,如果promise方法包裹的不是異步函數(shù),是普通的同步函數(shù),如果該同步代碼運行出錯,即便沒有調(diào)用reject方法時,后面的catch方法仍然能夠捕捉到這個錯誤,但如果同步代碼沒有出錯,沒有顯式調(diào)用resolve方法轉(zhuǎn)移的話,后續(xù)的then方法不會觸發(fā)。
七、高級示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
<!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實驗" ; //reject(1); resolve(1); //調(diào)用resolve將調(diào)用第一個then },2000); }).then( function (resolve){ return new Promise((resolve,reject)=>{ console.log( "這是狀態(tài)咩有敲定的promise,所以不會調(diào)用后面所有的then方法" ); //resolve(1)//沒有調(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+ " 沒有塊可以輸入!!" ); }).then(()=> { console.log( "finally it has been called!!" ); }) } </script> </body> </html> |
到此這篇關于關于javascript中的promise的用法和注意事項的文章就介紹到這了,更多相關js中promise用法內(nèi)容請搜索服務器之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://www.cnblogs.com/tanyui/archive/2021/01/14/14279650.html