淺析Promise

什麼是Promise?

Promise是ES6提供的一種解決異步編程的方案。web

Promise的本質是一個構造函數,咱們能夠使用new Promise來建立Promise實例對象,利用Promise對象的方法進行異步編程。ajax


爲何要使用Promise?

   1. Promise定義回調函數的方式更靈活。sql

使用純回調函數解決異步問題,回調函數必須在一開始就被指定,而Promise的回調函數能夠在啓動了異步任務後指定,甚至能夠在異步任務結束後指定。編程

   2. Promise能夠解決回調函數由於嵌套形成的回調地獄。promise

若是後面的異步操做,須要拿到前面異步操做的數據後才能執行,使用純回調函數,會出現層層嵌套的問題。形成的結果是代碼不易閱讀,不易維護。bash

Promise的三種狀態——pending、resolved、rejectedkoa

新建一個Promise對象時,初始的狀態爲pending(等待中),調用resolve(),狀態變爲resolved/fullfilled(成功)。調用reject(),狀態變爲rejected(失敗)。ssh

狀態一旦改變,就沒法再改變。也就是說,若是已經調用了resolve()和reject()中任意一個函數,再進行調用,Promise狀態不會再發生改變。異步


Promise的執行流程


簡述:一開始,咱們經過new Promise()建立一個Promise對象,此時的狀態爲pending。promise的參數接收兩個函數,分別是resolve和reject。在成功的時候調用resolve(),在失敗的時候調用reject()。resolve()和reject()中的任意一個被調用後,promise的狀態發生對應的改變(resloved/rejected)。resolve()和reject()的調用是promise狀態的標識,也是後續異步操做的指路燈。只有在狀態確認後,才能進行對應的成功/失敗的異步操做,也就是執行then/catch中的回調函數。執行完回調函數後,會返回一個新的Promise對象。ide


Promise代碼例子

const promise=new Promise((reslove,reject)=>{  //執行器函數(executor)--> 同步回調函數    setTimeout(()=>{        if(Date.now()%2==0){            //成功時調用resolve()            reslove('success '+Date.now());  //reslove和reject中均可以傳入值,且只能傳入一個值        }else{            //失敗時調用reject()            reject('failed '+Date.now());        }    },1000)})


//then和catch會接收在resolve和reject中傳入的數據

//1. then能夠接收resolve和reject的值(resolve在前,reject在後)promise.then(value=>{    console.log(value);  //onresolved回調函數  這裏的value接收的就是'success '+Date.now()},reason=>{    console.log(reason);  //onrejected回調函數  這裏的reason接收的就是'failed '+Date.now()})

//2. catch只能接收reject的值promise.then(value=>{    console.log(value); }).catch(reason=>{    console.log(reason);})

//3. 也能夠只接收成功/失敗的值promise.then(value=>{    console.log(value); })promise.then(null,reason=>{   console.log(reason); })複製代碼


promise中是先肯定狀態仍是先肯定回調?

咱們能夠經過定時器的方法人爲地改變狀態和回調的執行順序,無論怎樣都是能夠執行的。可是在程序執行的過程當中,永遠都是先確認狀態,再執行回調函數的。


JavaScript的執行機制宏任務和微任務 與 Promise

咱們都知道,JavaScript的執行是單線程的,同步任務會率先一件一件得在主線程完成,而異步任務會進入任務隊列,等待同步任務完成後執行。

而任務對列中還分爲了宏任務和微任務。

宏任務:script,DOM事件函數,ajax,定時器等。

微任務:promise等。

Promise做爲典型的微任務,須要注意的是new Promise中的回調函數(也就是執行器函數)是當即執行的,也就是說執行器函數是一個同步回調函數。而promise.then中回調函數纔是異步任務(微任務)

還有一點須要注意的是,promise.then中的回調函數必須在promise狀態肯定以後才能執行。下面是一個例子:

const promise1 = new Promise(function(resolve, reject) {    console.log(3);    setTimeout(function(){        resolve('Success!');        console.log(1);    },1000)});promise1.then(function(value) {    console.log(value);    console.log(2);});
//代碼輸出結果:3 (一秒後) 1 success!2
複製代碼

代碼開始運行後,先從最大的script宏任務開始,new promise直接執行,輸出3,setTimeout放入宏任務對列,緊接着的then被放入微任務隊列,而本該先執行的微任務,卻反而在宏任務結束以後才執行,這裏的執行順序顯然是不符合js的執行機制的。

如今,在這段代碼裏添加一行代碼。

const promise1 = new Promise(function(resolve, reject) {    console.log(3);    setTimeout(function(){        resolve('Success!');        console.log(1);    },1000)    resolve('haha');  //我是那行被添加的代碼});promise1.then(function(value) {    console.log(value);    console.log(2);});//代碼輸出結果:3 haha 2 (一秒後)1複製代碼

這時,輸出的結果就是then在前,setTimeout在後了。這行代碼改變的是promise的狀態。也就是說,then執行的前提是promise的狀態已經被肯定

在沒加代碼前,雖然在執行機制中then已經能夠執行,可是因爲promise的狀態未肯定,致使then沒法執行(then很苦惱,到底應該執行成功的回調仍是失敗的回調呢?),沒辦法,只好等待定時器結束狀態肯定下來再執行了。加了這行代碼後,狀態已經肯定,then天然就能夠在setTimeout前執行了。而且因爲狀態一旦肯定不能更改,因此setTimeout中的resolve('Success!')已經名不副實了。

相關文章
相關標籤/搜索