直接打印出來看看吧,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,報“圖片請求超時”的信息。


