ES6---new Promise()講解(尤其注意里面的參數resolve、reject)


直接打印出來看看吧,console.dir(Promise)。

 

 


這么一看就明白了,Promise是一個構造函數,自己身上有all、reject、resolve這幾個眼熟的方法,原型上有then、catch等同樣很眼熟的方法。這么說用Promise new出來的對象肯定就有then、catch方法嘍,沒錯。

 

Promise,簡單說就是一個容器,里面保存着某個未來才會結束的事件(通常是一個異步操作)的結果。從語法上說,Promise 是一個對象,從它可以獲取異步操作的消息。

Promise 提供統一的 API,各種異步操作都可以用同樣的方法進行處理。

Promise對象有以下兩個特點:

(1)對象的狀態不受外界影響。Promise對象代表一個異步操作,有三種狀態:Pending(進行中)、Resolved(已完成,又稱 Fulfilled)和Rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。

(2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:從Pending變為Resolved和從Pending變為Rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果。就算改變已經發生了,你再對Promise對象添加回調函數,也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。

有了Promise對象,就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。此外,Promise對象提供統一的接口,使得控制異步操作更加容易。

簡單來說,Promise 就是用同步的方式寫異步的代碼,用來解決回調問題

 

then()方法

then 方法就是把原來的回調寫法分離出來,在異步操作執行完后,用鏈式調用的方式執行回調函數。

而 Promise 的優勢就在於這個鏈式調用。我們可以在 then 方法中繼續寫 Promise 對象並返回,然后繼續調用 then 來進行回調操作。

可有兩個參數,第一個是成功 resolve 調用的方法,第二個是失敗 reject 調用的方法

下面做一個買筆寫作業上交的演示,它們是層層依賴的關系,下一步的的操作需要使用上一部操作的結果。(這里使用 setTimeout 模擬異步操作),正式開發可以用 ajax 異步

復制代碼
 1         //買筆
 2         function buy(){
 3             console.log("開始買筆");
 4             var p = new Promise(function(resolve,reject){
 5                 setTimeout(function(){
 6                     console.log("買了筆芯");
 7                     resolve("數學作業");
 8                 },1000);
 9             });
10             return p;
11         }
12         //寫作業
13         function work(data){
14             console.log("開始寫作業:"+data);
15             var p = new Promise(function(resolve,reject){
16                 setTimeout(function(){
17                     console.log("寫完作業");
18                     resolve("作業本");
19                 },1000);
20             });
21             return p;
22         }
23 
24         function out(data){
25             console.log("開始上交:"+data);
26             var p = new Promise(function(resolve,reject){
27                 setTimeout(function(){
28                     console.log("上交完畢");
29                     resolve("得分:A");
30                 },1000);
31             });
32             return p;
33         }
34         /* 不建議使用這種方式
35         buy().then(function(data){
36             return work(data);
37         }).then(function(data){
38             return out(data);
39         }).then(function(data){
40             console.log(data);
41         });*/
42 
43         //推薦這種簡化的寫法
44         buy().then(work).then(out).then(function(data){
45             console.log(data);
46         });
復制代碼

正式開發用ajax異步:

復制代碼
 1         var promise = new Promise(function(resolve,reject){
 2             $.ajax({
 3                 url:'/api/poisearch.json',
 4                 method:'get',
 5                 datatype:'json',
 6                 success:(res) =>{
 7                     resolve(res)
 8                 },
 9                 error:(err)=>{
10                     reject(err)
11                 }
12             });
13         });
14 
15         promise.then(function(res){
16             return res.data
17         }).then(function(data){
18             return data.result;
19         }).then(function(result){
20             console.log(result)
21         });
22 
23         //推薦使用箭頭函數簡寫成,極大提升了代碼的簡潔性和可讀性
24         promise.then(res => res.data).then(data => data.result).then(result => console.log(result));
復制代碼

 

reject()方法:

上面樣例我們通過 resolve 方法把 Promise 的狀態置為完成態(Resolved),這時 then 方法就能捕捉到變化,並執行“成功”情況的回調。

而 reject 方法就是把 Promise 的狀態置為已失敗(Rejected),這時 then 方法執行“失敗”情況的回調(then 方法的第二參數)

復制代碼
 1         function rebuy(){
 2             console.log("開始買筆");
 3             var p = new Promise(function(resolve,reject){
 4                 setTimeout(function(){
 5                     console.log("買筆失敗");
 6                     reject("沒帶夠錢");
 7                 },1000);
 8             });
 9             return p;
10         }
11 
12         function rework(data){
13             console.log("開始寫作業:"+data);
14             var p = new Promise(function(resolve,reject){
15                 setTimeout(function(){
16                     console.log("寫完作業");
17                     resolve("作業本");
18                 },1000);
19             });
20             return p;
21         }
22         
23         rebuy().then(rework,function(data){
24             console.log(data);
25         });
復制代碼

catch()方法:

1. 它可以和 then 的第二個參數一樣,用來指定 reject 的回調

復制代碼
 1        function rebuy(){
 2             console.log("開始買筆");
 3             var p = new Promise(function(resolve,reject){
 4                 setTimeout(function(){
 5                     console.log("買筆失敗");
 6                     reject("沒帶夠錢");
 7                 },1000);
 8             });
 9             return p;
10         }
11 
12         function rework(data){
13             console.log("開始寫作業:"+data);
14             var p = new Promise(function(resolve,reject){
15                 setTimeout(function(){
16                     console.log("寫完作業");
17                     resolve("作業本");
18                 },1000);
19             });
20             return p;
21         }
22 
23         rebuy().then(rework).catch(function(data){
24             console.log(data);
25         });    
復制代碼

2. 它的另一個作用是,當執行 resolve 的回調(也就是上面 then 中的第一個參數)時,如果拋出異常了(代碼出錯了),那么也不會報錯卡死 js,而是會進到這個 catch 方法中。

復制代碼
 1         function buy(){
 2             console.log("開始買筆");
 3             var p = new Promise(function(resolve,reject){
 4                 setTimeout(function(){
 5                     console.log("買了筆芯");
 6                     resolve("數學作業");
 7                 },1000);
 8             });
 9             return p;
10         }
11 
12         function work(data){
13             console.log("開始寫作業:"+data);
14             var p = new Promise(function(resolve,reject){
15                 setTimeout(function(){
16                     console.log("寫完作業");
17                     resolve("作業本");
18                 },1000);
19             });
20             return p;
21         }
22 
23         buy().then(function(data){
24             throw new Error("買了壞的筆芯");
25             work(data);
26         }).catch(function(data){
27             console.log(data);
28         });
復制代碼

all()方法:

Promise 的 all 方法提供了並行執行異步操作的能力,並且在所有異步操作執行完后才執行回調。

比如下面代碼,兩個個異步操作是並行執行的,等到它們都執行完后才會進到 then 里面。同時 all 會把所有異步操作的結果放進一個數組中傳給 then。

復制代碼
 1         //買作業本
 2         function cutUp(){
 3             console.log('挑作業本');
 4             var p = new Promise(function(resolve, reject){ //做一些異步操作
 5                 setTimeout(function(){
 6                     console.log('挑好購買作業本');
 7                     resolve('新的作業本');
 8                 }, 1000);
 9             });
10             return p;
11         }
12          
13         //買筆
14         function boil(){
15             console.log('挑筆芯');
16             var p = new Promise(function(resolve, reject){ //做一些異步操作
17                 setTimeout(function(){
18                     console.log('挑好購買筆芯');
19                     resolve('新的筆芯');
20                 }, 1000);
21             });
22             return p;
23         }
24 
25         Promise.all([cutUp(),boil()]).then(function(results){
26             console.log("寫作業的工具都買好了");
27             console.log(results);
28         });
復制代碼

 

race()方法:

race 按字面解釋,就是賽跑的意思。race 的用法與 all 一樣,只不過 all 是等所有異步操作都執行完畢后才執行 then 回調。而 race 的話只要有一個異步操作執行完畢,就立刻執行 then 回調。

注意:其它沒有執行完畢的異步操作仍然會繼續執行,而不是停止。

這里我們將上面樣例的 all 改成 race

1         Promise.race([cutUp(), boil()]).then(function(results){
2             console.log("哈哈,我先買好啦");
3 console.log(results); 4 });

 

race 使用場景很多。比如我們可以用 race 給某個異步請求設置超時時間,並且在超時后執行相應的操作。

請求某個圖片資源

復制代碼
 1        function requestImg(){
 2             var p = new Promise(function(resolve, reject){
 3             var img = new Image();
 4             img.onload = function(){
 5                resolve(img);
 6             }
 7             img.src = 'xxxxxx';
 8             });
 9             return p;
10         }
11          
12         //延時函數,用於給請求計時
13         function timeout(){
14             var p = new Promise(function(resolve, reject){
15                 setTimeout(function(){
16                     reject('圖片請求超時');
17                 }, 5000);
18             });
19             return p;
20         }
21          
22         Promise.race([requestImg(), timeout()]).then(function(results){
23             console.log(results);
24         }).catch(function(reason){
25             console.log(reason);
26         });
27         //上面代碼 requestImg 函數異步請求一張圖片,timeout 函數是一個延時 5 秒的異步操作。我們將它們一起放在 race 中賽跑。
28         //如果 5 秒內圖片請求成功那么便進入 then 方法,執行正常的流程。
29         //如果 5 秒鍾圖片還未成功返回,那么則進入 catch,報“圖片請求超時”的信息。
復制代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM