必須知道的 Promise 進階點(二)

很久沒寫博客了,今天終於把拖了很久的一篇寫完了。git

原文地址:必須知道的 Promise 進階點(二)github

前面還有:必須知道的 Promise 進階點(一)web

async/await 基礎

比起回調函數那看不懂的嵌套,Promise 要清爽很多,但當任務較多時, Promise 也有可能會有比較長的鏈和嵌套,這時候使用 async/await 就會讓代碼易讀不少。異步

async

async 函數能夠看做是 Promise 的語法糖:async

// resolve 狀態
async function foo() {
    console.log('start')
    return 'resolve'
}
foo().then(data => {
    console.log('data:', data)
})
console.log('end')
// start
// end
// data: resolve


// reject狀態
async function foo() {
    console.log('start')
    throw new Error('reject')
}
foo().catch(data => {
    console.log('data:', data.message)
})
console.log('end')
// start
// end
// data: reject
複製代碼

與下面直接使用 Promise 方式書寫的效果如出一轍:函數

// resolve 狀態
function foo() {
    return new Promise((resolve, reject) => {
        console.log('start')
        resolve('resolve')
    })
}
foo().then(data => {
    console.log('data:', data)
})
console.log('end')
// start
// end
// data: resolve


// reject狀態
function foo() {
    return new Promise((resolve, reject) => {
        console.log('start')
	reject('reject')
    })
}
foo().catch(data => {
    console.log('data:', data)
})
console.log('end')
// start
// end
// data: reject
複製代碼

await

await 與其字面意思同樣——等待,等待其後的函數執行完畢。ui

// resolve狀態
async function foo() {
    console.log('start')
    return 'resolve'
}
async function bar() {
    const data = await foo()
    console.log('data', data)
}
bar()
console.log('end')
// start
// end
// data resolve

// reject狀態
async function foo() {
    console.log('start')
    throw new Error('reject')
}
async function bar() {
    try {
        const data = await foo()
        console.log('data', data)
    } catch (err) {
	console.log('data', err.message)
    }
}
bar()
console.log('end')
// start
// end
// data reject
複製代碼

await 只能在 async 函數裏使用,不然會報錯spa

循環中的 async/await

首先思考下面兩個場景:code

  1. 有一個異步請求,須要屢次而且按順序發送隊列

  2. 有一個異步請求,須要屢次發送,但不用按順序

場景一

同一個請求,屢次,按順序。這就是一個典型的串行處理

function mockServer(i) {
    return new Promise((reslove, rejecy)=> {
        setTimeout(() => {
	    reslove('有值了:' + i)
        }, 1000 * i)
    })
}

async function getData(time) {
    var data = await mockServer(time)
    return data
}

var arr = [1,2,3,4]

async function showData() {
  console.time('showData')

  for (const item of arr) {
    const data = await getData(item)
    console.log(data)
  }
  console.timeEnd('showData')
}
showData()

// 有值了: 1
// 有值了: 2
// 有值了: 3
// 有值了: 4
// howData: 13100.510009765625ms
複製代碼

咱們經過 for-of 循環調用了 4 次異步函數 getData,因爲 getData 前面加了關鍵字 await,因此會依次排隊處理,一共花了13秒多的時間。

場景二

同一個請求,屢次,不按順序。這就是一個典型的並行處理,每一個請求同時發送,而不用排隊等候,節約時間。

function mockServer(i) {
    return new Promise((reslove, rejecy)=> {
        setTimeout(() => {
	    reslove('有值了:', i)
        }, 1000 * i)
    })
}

async function getData(time) {
    var data = await mockServer(time)
    return data
}

var arr = [1,2,3,4]

async function showData() {
  console.time('showData')

  var allAsyncRequest = arr.map(item => getData(item))
  for await  (const asyncRequest of allAsyncRequest) {
    const data = asyncRequest
    console.log(data)
  }
  console.timeEnd('showData')
}
showData()

// 有值了: 1
// 有值了: 2
// 有值了: 3
// 有值了: 4
// showData: 4131.318115234375ms
複製代碼

咱們在 map 的回調裏調用了 4 次異步請求函數,將請求事件放到事件隊列裏面,讓 4 個請求能夠同時處理,而不影響後續任務的執行。

而後再經過 for await...of 來等待 4 個異步請求都執行完,一共花了 4 秒,大大節約了時間。

這裏的 for await...of 還能夠換一種寫法:

for (const asyncRequest of allAsyncRequest) {
    const data = await asyncRequest
    console.log(data)
}
複製代碼

也可使用 Promise.all()

Promise.all(allAsyncRequest).then((data) => {
    console.log(data)
    console.timeEnd('showData')
})

// ["有值了:1", "有值了:2", "有值了:3", "有值了:4"]
// showData: 4441.679931640625ms
複製代碼

注意:這裏不能使用 forEach 來進行循環處理,具體緣由能夠看 當async/await趕上forEach,這篇文章已經寫的很清楚了。

最後

學會熟練使用 async/await,能夠很好提高代碼的可閱讀和可維護性,你們若是還有更好的用法和建議,歡迎在評論區補充。

相關文章
相關標籤/搜索