您當前的位置:首頁 > 旅遊

JS---Promise入門篇

作者:由 淺笑一世繁華 發表于 旅遊時間:2020-05-10

這篇文章適合要接觸Promise的朋友們閱讀,裡面寫的是Promise中的一些基礎知識,並沒有涉及到太難理解的。

一、 初識Promise

1.1 什麼是Promise

Promise:ES6中新提供的一個內建類(提到類可以想到new、原型、原型鏈、例項。。。),基於promise可以有效的管理JS中的非同步程式設計,解決傳統非同步程式設計+回撥函式導致的‘回撥地獄’問題。

=> 我們把基於promise進行非同步管控的模式叫做‘promise設計模式’

1.2 學習Promise需要掌握的內容

從函式有三個角色入手:普通函式、建構函式(類)、普通物件

【普通物件 => 靜態的私有屬性方法】

promise。all()

promise。race()

promise。resolve()

promise。reject()

【類 => 原型鏈上的公共屬性和方法】

promise。prototype。then()

promise。prototype。catch()

promise。prototype。finally() [一般不用]

【new建立例項】

二、建立Promise例項

2.1 建立Promise例項的語法

語法:

let 例項 = new Promise([executor])

說明:

必須傳一個函式,否則會報錯:Uncaught TypeError: Promise resolver undefined is not a function

[executor]

是一個函式,我們一般在函式中管控我們的非同步程式設計程式碼

new Promise

的時候就會把

executor

立即執行

並且給

executor

函式傳遞兩個實參(兩個實參也都是函式):

resolve/reject

let p1 = new Promise(); //必須傳一個函式 Uncaught TypeError: Promise resolver undefined is not a function

let p2 = new Promise((resolve,reject)=>{

//非同步程式設計程式碼

});

2.2 Promise的兩個值

Promise的例項擁有[[PromiseStatus]]/[[PromiseValue]]

[[PromiseStatus]]是promise狀態(要麼是成功態要麼是失敗態)

準備狀態

pending

new Promise

的時候預設狀態就是

pending

成功狀態

fulfilled/resolved

:一般在非同步操作成功後,我們透過執行

resolved

函式,可以把

promise

的狀態改為

resolved

失敗狀態

rejected

:一般在非同步操作失敗後,我們透過執行

reject

函式,可以把

promise

的狀態改為

rejected

pending

=>

resolved / rejected

只要狀態一旦更改,則不可以再改變

[[PromiseValue]]是promise的值

不論執行

resolve/reject

哪個函式,都可以傳遞值,傳遞的值最後賦值給

[[PromiseValue]]

例如

: 我們建立一個Promise例項p1,建立例項的時候我們在函式中把他的resolved函式執行,也就是把它變為成功態

let p1 = new Promise((resolve, reject) => {

setTimeout(() => {

resolve(‘ok’);

console。log(p1) //=>‘resolve’ ‘ok’

}, 1000)

});

console。log(p1); //=>‘padding’ undefined

JS---Promise入門篇

2.3 總結:建立例項時做的事情

我們在建立一個Promise的例項,需要給Promise傳遞一個函式,這個函式會立即執行,並且瀏覽器給它自帶兩個引數(兩個引數也都是函式),這兩個引數會改變Promise的狀態和值

三、Promise原型鏈上的公共方法---then

3.1 then是幹什麼的

我們在建立例項的時候可以修改Promise的狀態,目的就是為了控制then中的兩個方法,哪一個去執行。

then

方法:

例項。then([狀態成功時執行的],[狀態失敗時執行的])

result / reason

接收的是

[[PromiseValue]]

的資訊(在

executor

函式中,基於

resolve/reject

執行傳遞的值,就是給

promise-value

傳遞的值,並且只能傳遞一個值,傳遞第二個實參沒用)

let p1 = new Promise((resolve, reject) => {

setTimeout(() => {

if (Math。random() < 0。5) {

reject(‘NO’);

} else {

resolve(‘OK’);

}

}, 1000);

});

p1。then(result => {

console。log(`成功:${result}`);

}, reason => {

console。log(`失敗:${reason}`); //當上面的隨機是小於0。5的時候執行reject,也就是把狀態改為失敗態,從而執行then中的reason這個方法

});

3.2 then方法在什麼時候執行?

1. 建立例項時執行的是非同步程式碼:

非同步請求放置在

EXECUTOR

中,請求成功或者失敗後做啥事情都寫在

THEN

2. 建立例項時執行的不是非同步程式碼:

EXECUTOR

函式中理論上是管控非同步程式設計程式碼的,但是在開發中,你可以自己隨意處理;但是不論怎麼處理,

THEN

中的方法,只會在

PROMISE

狀態變為成功或者失敗的狀態下才會執行;

EXECUTOR

函式中執行

RESOLVE

或者

REJECT

,並不一定會立即通知

THEN

中的方法執行;如果在這兩個函式執行之前,已經基於

THEN

把成功或者失敗的方法放置好了,則立即通知執行;如果還沒有執行過

THEN

方法,則需要等到

THEN

執行後,方法放置好,再通知成功或者失敗的方法執行!

new Promise((resolve, reject) => {

// 非同步請求放置在EXECUTOR中,請求成功或者失敗後做啥事情都寫在THEN中

$。ajax({

url: ‘/api/info’,

method: ‘get’,

success: result => {

resolve(result);

},

error: reject

});

})。then(result => {

}, reason => {

});

new Promise((resolve, reject) => {

reject(100);

})。then(result => {

console。log(`成功:${result}`);

}, reason => {

console。log(`失敗:${reason}`);

});

3.3 then方法的返回值

每一次執行

。then

都會返回一個新的

Promise

例項(初始狀態:

pending

初值:

undefined

)。這樣可以繼續

。then

下去,這就是

Promise

中的

then

鏈機制

下面的例子說明:

p2這個例項的成功或者失敗狀態,是由

p1。then

這堆程式碼決定的

第一種情況:只要

p1。then

中不論哪個方法執行,

只要不報錯

,新的p2例項的狀態都會變為

成功態

,而方法返回的結果就是p2例項的

promise-value

值(也就是上一個

then

執行的返回結果,會傳遞給下一個

then

中的方法);同理,兩個方法中,

不管哪一個執行報錯,P2一定是失敗態

第二種情況:如果

p1。then

中的某個方法執行,返回的是新的

Promise

例項,則會等待這個

Promise

的執行結果,作為p2的執行狀態

let p1 = new Promise((resolve, reject) => {

setTimeout(() => {

if (Math。random() < 0。5) {

reject(‘NO’);

} else {

resolve(‘OK’);

}

}, 1000);

});

let p2 = p1。then(result=>{

},reason=>{

});

console。log(p2);

let p3 = p2。then(result => {

console。log(result); //=>‘OK@@’

// return Promise。resolve(100); //=>P3的狀態變為成功,值是100

return Promise。reject(0); //=>P3的狀態變為失敗,值是0

}, reason => {

});

p3。then(result => {

console。log(‘成功’ + result);

}, reason => {

console。log(‘失敗’ + reason);

});

3.4 then鏈的理解

下面程式碼的輸出結果:把這段程式碼理解會then就掌握差不多了(鏈有點長 ,不著急,下面搭配了註釋 )

new Promise(resolve => {

setTimeout(() => {

resolve(10); //1000MS後 第一個PROMISE例項狀態是成功 VALUE:10

}, 1000);

})。then(result => {

console。log(`成功:${result}`); //=>‘成功:10’

return result * n; //報錯:ReferenceError: n is not defined 也就是讓此次THEN返回的PROMISE例項變為失敗態,VALUE:失敗的原因

}, reason => {

console。log(`失敗:${reason}`);

return reason * 10;

})。then(result => {

console。log(`成功:${result}`);

return result * 20;

}, reason => {

console。log(`失敗:${reason}`); //=>‘失敗: ReferenceError: n is not defined’

return reason * 10; //NaN 程式碼執行沒有報錯,讓當前THEN返回的例項狀態:成功 VALUE:NAN

})。then(result => {

console。log(`成功:${result}`); //=>‘成功:NaN’

return result * 20; //NaN 程式碼執行沒有報錯,讓當前THEN返回的例項狀態:成功 VALUE:NAN

}, reason => {

console。log(`失敗:${reason}`);

return reason * 10;

})。then(result => {

console。log(`成功:${result}`); //=>‘成功:NaN’

return Promise。reject(result * 20); //返回的新的失敗的PROMISE例項影響了本次THEN返回PROMISE例項的狀態和結果(和RETURN的保持一致)

}, reason => {

console。log(`失敗:${reason}`);

return Promise。resolve(reason * 10);

})。then(result => {

console。log(`成功:${result}`);

}, reason => {

console。log(`失敗:${reason}`); //=>‘失敗:NaN’

});

3.5 then中只寫一個方法的理解

THEN

中只設置一個方法,成功或者失敗執行的方法沒有設定,會順延到下一個

THEN

中查詢(依然是按照當前的狀態查詢,例如:失敗的狀態,第一個

THEN

沒有設定失敗的方法,會找第二個

THEN

中設定的失敗的方法。。。)

比如麼有設定

reason

,那麼需要執行它的時候預設做的是什麼事情呢?

=> { 不寫的情況下,

PROMISE

內部預設補充了一下(實現的效果:繼續找下一個

THEN

中代表失敗的)}

=> 即執行的是這句程式碼(因為是執行的失敗態,所以返回的例項是失敗態):

return Promise。reject(reason);

說了這麼多,到底理解不理解 ,哈哈上程式碼 (內心是拒絕的,因為它肯定也會是很長的then鏈)

new Promise((resolve, reject) => {

setTimeout(() => {

reject(10); //狀態:失敗 值:10

}, 1000);

})。then(result => {

console。log(`成功:${result}`);

return result * 10;

})。then(result => {

console。log(`成功:${result}`);

return result * 10;

})。then(null, reason => {

console。log(`失敗:${reason}`); //=>‘失敗:10’

return reason * 2;

//程式碼執行沒有報錯,讓當前例項狀態:成功 值:20

})。then(null,reason => {

console。log(`失敗:${reason}`);

return reason * 2;

})。then(result => {

console。log(`成功:${result}`); //=>‘成功:20’

});

四、Promise.all()

Promise。all([PROMISE1,PROMISE2,。。。])

:等待所有的

PROMISE

例項都成功,整體才是成功的(返回新的

PROMISE

例項),只要有一個例項是失敗的,整體例項就是失敗的;

function fn1() {

return new Promise(resolve => {

setTimeout(_ => {

resolve(10);

}, 2000);

});

}

function fn2() {

return Promise。resolve(20);

}

function fn3() {

return new Promise(resolve => {

setTimeout(_ => {

resolve(30);

}, 500);

});

}

Promise。all([fn1(), fn2(), fn3()])。then(results => {

// 只有當三個PROMISE例項都成功的時候(等待最晚有結果的一個也是成功),才會觸發執行,results會按照放置的順序,儲存著每一次獲取的結果

console。log(results); //=>[10, 20, 30]

});

五、Promise.race()

Promise。race()

同時傳送多個請求,誰先有處理結果(不管結果是成功還是失敗),就以誰的結果為主(哪怕是失敗的)

六、【補充】:異常捕獲

6.1 catch表示then 中只寫一個reason方法

在專案中,我們會用

CATCH(REASON=>{})

代替

THEN(NULL,REASON=>{})

,效果是一模一樣的(執行

CATCH

也會返回新的

PROMISE

例項,裡面設定的方法是在例項為失敗狀態下執行的)

=>在專案中,我們一般

THEN

中放的是成功執行的,

CATCH

中放的是失敗執行的

new Promise((resolve, reject) => {

setTimeout(() => {

reject(10);

}, 1000);

})。then(result => {

console。log(`成功:${result}`);

return result * 10;

})。catch(reason => {

console。log(`失敗:${reason}`);

return reason * 2;

});

6.2 異常捕獲:try catch

為什麼要用try catch?

比如下面的程式碼:我們輸出一個從來沒有定義過的變數,會報錯,下面的程式碼也不再執行,但是我們想讓下面的程式碼繼續執行,就需要用到

try catch

console。log(n); //=>Uncaught ReferenceError: n is not defined 瀏覽器丟擲異常資訊,下面程式碼就不會再執行了

console。log(‘OK’);

try catch

try

:把可能會報錯的程式碼放置到

try

中捕獲異常(程式碼執行一但報錯,控制檯是不丟擲異常的,不會影響後續程式碼的執行)

catch

catch

中捕獲到異常資訊 (可以把資訊上報給伺服器)

try {

// 把可能會報錯的程式碼放置到TRY中捕獲異常(程式碼執行一但報錯,控制檯是不丟擲異常的,不會影響後續程式碼的執行)

console。log(n);

} catch (error) {

// CATCH中捕獲到異常資訊 (可以把資訊上報給伺服器)

// console。log(error);

}

console。log(‘OK’);

標簽: promise  Result  reason  log  console