Promise && async/await的理解和用法

Promise && async/await的理解和用法

爲何須要promise(承諾)這個東西

在以前咱們處理異步函數都是用回調這個方法,回調嵌套的時候會發現 閱讀性 和 調試 的難度會增長不少;

怎麼理解promise

想象一下,你把一個任務交給一個不錯的小夥子,他叫承諾;不用擔憂你交給他的任務會丟失,他總會返回的,作成功了resolve,失敗了reject;node

var promise = new Promise((resolve, reject) =>{
    //交給給「承諾」同窗一個異步任務
    setTimeout(()=>{
        if(true){
            // 成功了,返回params
            resolve('params')
        }else{
            // 失敗了,返回error
            reject('error')
        }
    }, 1000) 
})

// 上面是給承諾一個任務,下面是"承諾"同窗的返回
promise.then((res)=>{
    console.log(res)
}).catch((rej)=>{   
    console.log(res)
})

怎麼使用promise

實際狀況中,異步的場景沒有那麼簡單,你能夠會遇到下面這些場景git

  1. 「串行應用場景」下的處理方案
let promise = new Promise((res, rej)=>{
    asyncFunc('promise', 1000, res, rej)
}) 

promise.then(res=>{
    console.log(res);
    return new Promise((res, rej)=>{
        asyncFunc('second', 2000, res, rej)
    })
}).then(res=>{
    console.log(res);
    return new Promise((res, rej)=>{
        asyncFunc('third', 1000, res, rej)
    })
    // throw 'oh, no!';
}).then(res=>{
    console.log(res);
    console.log('endinggggggg')
}).catch(err=>{
    console.log('catch', err)
})
  1. 「並行應用場景」的處理方案(即在全部的異步操做完成以後執行)
let promise1 = new Promise((res, rej)=>{
    asyncFunc('promise1', 1000, res, rej)
})

let promise2 = new Promise((res, rej)=>{
    asyncFunc('promise2', 2000, res, rej)
})

let promise3 = new Promise((res, rej)=>{
    asyncFunc('promise3', 1000, res, rej)
})

var promiseAll = Promise.all([promise1, promise2, promise3])
promiseAll.then(res =>{
    console.log('最終的結果', res)
}).catch(err =>{
    console.log('catch', err);
})
  1. 「競速模式下」,如字面意思,只要是哪個提早完成了。就表示整個狀態處理完成狀態;這個場景能夠發散成若是是超過了3s我就不去作這件事情了
let promise1 = new Promise((res, rej)=>{
    asyncFunc('promise1', 1000, res, rej, true)
})

let promise2 = new Promise((res, rej)=>{
    asyncFunc('promise2', 2000, res, rej, true)
})

let promise3 = new Promise((res, rej)=>{
    asyncFunc('promise3', 1000, res, rej)
})

// 1000s的任務完成了,就直接返回promise1了
var promiseRace = Promise.race([promise1, promise2, promise3])
promiseRace.then(res =>{
    console.log('最終的結果', res)
}).catch(err =>{
    console.log('catch', err);
})

js是單線程,promise,setTimeout的執行優先級

講這一塊的東西就得講講nodejs的事件處理機制;
事件隊列應該是一個數據結構,全部的事情都被事件循環排隊和處理,直到隊列爲空。可是Node中的這種狀況與抽象反應器模式如何描述徹底不一樣。
下面講的東西只適合V8;

NodeJS中有許多隊列,其中不一樣類型的事件在本身的隊列中排隊。github

在處理一個階段以後而且在移到下一個隊列以前,事件循環將處理兩個中間隊列,直到中間隊列中沒有剩餘的項目。web

定義:

有四種主要類型,由libuv事件循環處理;promise

  • 過時的定時器和間隔隊列 - (好比使用setTimeout,setInterval);
  • IO事件隊列 - 已完成的IO事件
  • Immediates隊列 - 使用setImmediate功能添加回調
  • 關閉處理程序隊列 - 任何close事件處理程序

還有2箇中間隊列,不屬於libuv自己的一部分,可是是nodejs的一部分;安全

  • Next Ticks Queue - 使用process.nextTick 函數添加回調;(優先級更高)
  • 其餘微型任務隊列 - 包括其餘微型任務,例如已經解決的承諾回調;
如何工做的:

image

上圖是node中libuv模塊在處理異步I/O操做的流程圖; 數據結構

Node經過定時器檢查隊列中的任何過時定時器來啓動事件循環,並在每個步驟中遍歷每個隊列。若是沒有任務則循環退出,每一次隊列處理都被視爲事件循環的一個階段。特別有意思的是中間紅色的隊列,每次階段都會優先去處理中間隊列的任務。而後再去處理其餘的隊列。異步

什麼是async/await

async/await 能夠是Generator和promise結合實現的;

注意核心點:

  • asnyc 函數老是返回一個Promise對象,不論函數是否return Promise;
  • await 後面跟着Promise對象,若是不是Promise對象,也會被封裝成Promise;
  • async/await 和Promise對象在本質上是同樣的
其餘note點
  1. await的任何內容都經過Promise.resolve()傳遞,這樣就能夠安全的await非原生Promise;
  2. 構造函數以及getter/settings方法不能是異步的;
  3. 儘管編寫的是同步的代碼,可是也不要錯失並行執行的機會,否則你須要消耗等待的性能喪失;
  4. Babel REPL 提及來頗有趣。試試就知道。

怎麼用async/await

實際狀況中,異步的場景沒有那麼簡單,你能夠會遇到下面這些場景
  1. 場景:只有一個await而且 resolve
const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout));
async function f(){
    await delay(1000);
    await delay(2000);
    await delay(3000);
    return 'done'
}
f().then(v=> console.log(v));
  1. 場景:只有一個await而且 reject
let a;
async function g(){
    await Promise.reject('error');
    a = await 1;
}
g().then(v=>console.log(v)).catch(err=>console.log(err));
  1. 場景:有多個await, 能夠用try/catch
let a ;
async function g(){
    try{
        await Promise.reject('error')
    }catch(err){    
        console.log(err)
    }
    a= await 1;
    return a;
}

g().then(v=>console.log(v)).catch(err=>console.log(err));
  1. 場景:等待平行任務
async function series(){
    const await1 = delay(1000);
    const await2 = delay(1000);
    await await1;
    await await2;
    return 'done'
}
series();

歡迎提意見和star

若是有不對的能夠提issue
若是以爲對你有幫助能夠star下
githubasync

參考文檔

  1. 這一系列的文檔講的很不錯

https://juejin.im/post/5b777f...ide

  1. 講promise,setTimeout優先級的;nodejs中事件循環中的任務優先級

https://jsblog.insiderattack....

  1. developers.google.com域名下面的文檔仍是頗有質量的,其中會比較全面的介紹怎麼去用promise和async/await

https://developers.google.com...

相關文章
相關標籤/搜索