js中的promise詳解


一 概述

  Promise是異步編程的一種解決方案,可以替代傳統的解決方案--回調函數和事件。ES6統一了用法,並原生提供了Promise對象。作為對象,Promise有一下兩個特點: * (1)對象的狀態不受外界影響。 * (2)一旦狀態改變了就不會在變,也就是說任何時候Promise都只有一種狀態。

二 Promise的狀態

  Promise有三種狀態,分別是:**Pending **(進行中), ** Resolved **(已完成),** Rejected ** (已失敗)。Promise從Pending狀態開始,如果成功就轉到成功態,並執行resolve回調函數;如果失敗就轉到失敗狀態並執行reject回調函數。下面是Promise的規范圖解,圖源百度圖片:
![](https://img2018.cnblogs.com/blog/1195929/201903/1195929-20190320105311412-1850385921.png)

三 基本用法

   可以通過Promise的構造函數創建Promise對象。
var promise = new Promise(function(resolve,reject)
setTimeout(function(){                              
  console.log("hello world");},2000);
});    

  Promise構造函數接收一個函數作為參數,該函數的兩個參數是resolvereject,它們由JavaScript引擎提供。其中resolve函數的作用是當Promise對象轉移到成功,調用resolve並將操作結果作為其參數傳遞出去;reject函數的作用是單Promise對象的狀態變為失敗時,將操作報出的錯誤作為其參數傳遞出去。如下面的代碼:

    function greet(){
    var promise = new Promise(function(resolve,reject){
        var greet = "hello  world";
        resolve(greet);
    });
    return promise;
    }
    greet().then(v=>{
    console.log(v);//*
    })

上面的*行的輸出結果就是greet的值,也就是resolve()傳遞出來的參數。

注意:創建一個Promise對象會立即執行里面的代碼,所以為了更好的控制代碼的運行時刻,可以將其包含在一個函數中,並將這個Promise作為函數的返回值。

四 Promise的then方法

  promise的then方法帶有以下三個參數:成功回調,失敗回調,前進回調,一般情況下只需要實現第一個,后面是可選的。Promise中最為重要的是狀態,通過then的狀態傳遞可以實現回調函數鏈式操作的實現。先執行以下代碼:

function greet(){
var promise = new Promise(function(resolve,reject){
    var greet = "hello  world";
    resolve(greet);
});
return promise;
}
var p = greet().then(v=>{
console.log(v);
})

console.log(p);

改程序的輸出為:


從中可以看出promise執行then還是一個promise,並且Promise的執行是異步的,因為hello world在最后一條輸出語句的前面就打印出來,且Promise的狀態為pending(進行中)。
  因為Promise執行then后還是Promise,所以就可以根據這一特性,不斷的鏈式調用回調函數。下面是一個 例子:

function greet(){
    var promise = new Promise(function(resolve,reject){
        var greet = "hello  world";
        resolve(greet);
    });
    return promise;
}
greet().then(v=>{
    console.log(v+1);
    return v;
})
.then(v=>{
    console.log(v+2);
    return v;
})
.then(v=>{
    console.log(v+3);
})

五 Promise的其他方法

reject用法

  reject的作用就是把Promise的狀態從pending置為rejected,這樣在then中就能捕捉到reject的回調函數
function judgeNumber(num){
    var promise1 = new Promise(function(resolve,reject){
        num =5;
        if(num<5){
            resolve("num小於5,值為:"+num);
        }else{
            reject("num不小於5,值為:"+num);
        }
    });
    return promise1;
}

judgeNumber().then(
    function(message){
        console.log(message);
    },
    function(message){
        console.log(message);
    }
)

.then后包含有兩個方法,前一個執行resolve回調的參數,后一個執行reject回調的參數。

catch用法

function judgeNumber(num){
    var promise1 = new Promise(function(resolve,reject){
        num =5;
        if(num<5){
            resolve("num小於5,值為:"+num);
        }else{
            reject("num不小於5,值為:"+num);
        }
    });
    return promise1;
}

judgeNumber().then(
    function(message){
        console.log(message);
    }
)
.catch(function(message){
    console.log(message);
})

這個時候catch執行的是和reject一樣的,也就是說如果Promise的狀態變為reject時,會被catch捕捉到,不過需要特別注意的是如果前面設置了reject方法的回調函數,·則catch不會捕捉到狀態變為reject的情況。catch還有一點不同的是,如果在resolve或者reject發生錯誤的時候,會被catch捕捉到,這與java,c++的錯誤處理時一樣的,這樣就能避免程序卡死在回調函數中了。

all用法

  Promise的all方法提供了並行執行異步操作的能力,在all中所有異步操作結束后才執行回調。
function p1(){
    var promise1 = new Promise(function(resolve,reject){
        console.log("p1的第一條輸出語句");
        console.log("p1的第二條輸出語句");
        resolve("p1完成");
    })
    return promise1;
}

function p2(){
    var promise2 = new Promise(function(resolve,reject){
        console.log("p2的第一條輸出語句");
        setTimeout(()=>{console.log("p2的第二條輸出語句");resolve("p2完成")},2000);

    })
    return promise2;
}

function p3(){
    var promise3 = new Promise(function(resolve,reject){
        console.log("p3的第一條輸出語句");
        console.log("p3的第二條輸出語句");
        resolve("p3完成")
    });
    return  promise3;
}

Promise.all([p1(),p2(),p3()]).then(function(data){
    console.log(data);
})

運行結果如下:


這里可以看到p2的resolve放到一個setTimeout中,最后的.then也會等到所有Promise完成狀態的改變后才執行。

race用法

  在all中的回調函數中,等到所有的Promise都執行完,再來執行回調函數,race則不同它等到第一個Promise改變狀態就開始執行回調函數。將上面的`all`改為`race`,得到
Promise.race([p1(),p2(),p3()]).then(function(data){
    console.log(data);
})

其運行結果為:

紅框中圈出了"p1完成"字樣,說明當執行then()方法時,只有第一個promise的狀態改變了。

這里還需要注意一個問題,promise的執行時異步的,比如下面這樣:

var i

var promise = new Promise(function(resolve,reject){
    resolve("hello");
})

promise.then(data=>{
    i = 2;

})
console.log(i);

得到的結果是undefined,這不是因為promise不能改變外部的值,而是因為當執行console.log(i)時,then()方法還沒執行完。如果你將console.log(i)延遲輸出就可以得到正確的結果:

setTimeout(()=>console.log(i),1000);

所以不要在promise后面執行一些依賴promise改變的代碼,因為可能promise中的代碼並未執行完,或者你可以將其延遲輸出。


免責聲明!

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



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