天天看點

一看就懂的async-awaitasync-await異步處理和使用async-await基本使用asyncawait回調執行個體小心并行處理

一看就懂的async-await

  • async-await異步處理和使用
  • async-await基本使用
  • async
  • await
  • 回調執行個體
  • 小心并行處理

async-await異步處理和使用

好不容易看完了

Promise

心想着可算是能用一下了,結果就看到了各種标題為:有了

async-await以後promise還有必要學習嗎?

async await優于promise的幾個特點

。。。然後我就懵圈了,我的内心emmmmm。

原來,

async-await

promise

generator

的文法糖,隻是為了讓我們書寫代碼更加流暢,增強代碼的可讀性,簡而言之:

async-await

是建立在

promise

機制之上的,并不能取代

promise

async-await基本使用

async

函數傳回一個

Promise

對象,可以使用

then

方法添加回調函數。

當函數執行的時候,一旦遇到

await

就會先傳回,等到異步操作完成,再接着執行函數體内後面的語句。

function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms)
  })
}

async function asyncPrint(value, ms) {
  await timeout(ms)
  console.log(value)
}

asyncPrint('hello world', 2000);
//hello world (2s後)
           

上面代碼指定2000毫秒以後,輸出

hello world

。同時函數

asyncPrint()

執行結果傳回了一個

promise

對象。

async

async

用來表示函數是異步的,定義的函數會傳回一個

promise

對象,可以使用

then

方法添加回調函數,而

async

函數内部

return

語句傳回的值,就會成為

then

方法回調函數的參數。針對上面的

asyncPrint

例子來看,如果我們直接使用

then

會發現什麼都沒有

function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms)
  })
}

async function asyncPrint(value, ms) {
  await timeout(ms)
  console.log(value)
}

asyncPrint('hello world', 2000).then((value)=>{console.log(value)})
//hello world (2s後)
//undefined
           

因為函數

asyncPrint

内部沒有

return

語句傳回值,那我們加上

return

試一下

function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms)
  })
}

async function asyncPrint(value, ms) {
  await timeout(ms)
  console.log(value)
  return 'done'
}

asyncPrint('hello world', 2000).then((value)=>{console.log(value)})
//hello world (2s後)
//done
           

其實就是相當于執行了

Promise.resolve('done')

,如果沒有

return

就相當于

Promise.resolve()

await

await

後面可以跟任何JS表達式,雖然

await

可以跟很多類型的東西,但是最主要的意圖是用來等待

Promise

對象的狀态被

resolved

,如果

await

的是

promise

對象會造成異步函數停止執行并等待

promise

解決,如果等到的是正常的表達式就立即執行,還是開頭的那個例子,如果

await

的不是

promise

對象會怎麼樣

function timeout(ms) {
  setTimeout(()=>{}, ms)
}

async function asyncPrint(value, ms) {
  await timeout(ms)
  console.log(value)
}

asyncPrint('hello world', 2000);
//hello world (立即)
           

因為

await

後面不是promise對象了,也就不需要等待結果傳回了,是以到這就直接往下執行了。

再來一個例子

function sleep(second) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('enough sleep~');
        }, second);
    })
}
function normalFunc() {
    console.log('normalFunc');
}
async function awaitDemo() {
    await normalFunc();
    console.log('something, ~~');
    let result = await sleep(2000);
    console.log(result);// 兩秒之後會被列印出來
}
awaitDemo();
// normalFunc
// something, ~~
// ---2s後---
// enough sleep~
           

第一個

await

後面是一個正常表達式是以直接執行後繼續往下執行,然後再遇到第二個

await

,這個

await

後面是一個異步操作,是以需要等待結果傳回并執行後再繼續往下執行,也就是過了2s以後再列印最後的值。

回調執行個體

舉例說明,假設有三個請求需要發生,第三個請求是依賴第二個請求的解析,第二個請求是依賴第一個請求的解析

如果要用ES5實作就會有三個回調

如果用Promise就會至少有三個then

一個是橫向代碼很長,一個是縱向代碼很長,如果用

async-await

來實作呢?

//我們仍然使用 setTimeout 來模拟異步請求
    function sleep(second, param) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(param);
            }, second);
        })
    }

    async function test() {
        let result1 = await sleep(1000, 'req01');
        console.log(result1)
        let result2 = await sleep(1000, 'req02' + result1);
        console.log(result2)
        let result3 = await sleep(1000, 'req03' + result2);
        console.log(result3)
    }

    test();
    //req01 --1s後--
    //req02req01 --2s後--
    //req03req02req01 --3s後--
           

難怪說

async-await

promise

的文法糖了,其實還是

promise

,隻是代碼閱讀起來讓你覺得它好像是一個同步請求,不用那麼多回調或者

then

了。amazing!!!

小心并行處理

如果有多個await指令後面的異步操作之間不存在互相依賴的關系,那我們當然就不能使用上面執行個體中的方法來使用async-await了

例如有三個異步請求需要發送,但是互相之間沒有關聯,要做的其實就是當所有異步請求結束後清除界面上的loading,如果我們像上面那樣使用當最後一個請求結束後清除loading,其實等待的時間就是三個請求時間之和:

function sleep(second) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('sth');
        }, second);
    })
}

async function clearLoad() {
    await sleep(1000);
    await sleep(1000);
    await sleep(1000);
    console.log('清除loading啦');
}

clearLoad();
// 清除loading啦 --3s後--
           

其實這裡真正的需求是當最慢的那個請求發送結束了,就可以清除loading了,是以改良後是這樣:

function sleep(second) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('sth');
        }, second);
    })
}

async function clearLoad() {
    let p1 = sleep(1000);
    let p2 = sleep(1000);
    let p3 = sleep(1000);
    await Promise.all([p1, p2, p3]);
    console.log('清除loading啦');
}

clearLoad();
// 清除loading啦 --1s後--
           

是以,以上可以得出:

async-await

promise

的文法糖,讓我們書寫代碼更加流暢,增強代碼的可讀性,它是建立在

promise

機制之上的,并不能取代

promise