JavaScript中的Promise和async/await


一、同步與異步有何不同:

1.JavaScript是單線程的語言

2.異步不會阻塞代碼執行

3.同步會阻塞代碼執行

 

二、異步的應用場景:需要等待的情況

1.網絡請求,如ajax圖片加載

2.定時任務,如setTimeout

 

三、promise的基本使用:

1.通過串行的方式解決了回調地獄的問題

2.手寫promise加載圖片:

function loadImg(src) { const p = new Promise( (resolve, reject) => { const img = document.createElement('img') img.onload = () => { resolve(img) } img.onerror = () => { const err = new Error(`圖片加載失敗 ${src}`) reject(err) } img.src = src } ) return p } const url1 = 'https://img.mukewang.com/5a9fc8070001a82402060220-140-140.jpg' const url2 = 'https://img3.mukewang.com/5a9fc8070001a82402060220-100-100.jpg' loadImg(url1).then(img1 => { console.log(img1.width) return img1 // 普通對象
}).then(img1 => { console.log(img1.height) return loadImg(url2) // promise 實例
}).then(img2 => { console.log(img2.width) return img2 }).then(img2 => { console.log(img2.height) }).catch(ex => console.error(ex))

 

四、promise的狀態:

1.三種狀態:

(1)pending(過程中)、resolved(解決了,也叫fulfilled)、rejected(失敗了)

(2)pending => resolved 或 pending => rejecte

(3)變化不可逆

// 剛定義時,狀態默認為 pending
const p1 = new Promise((resolve, reject) => { }) // 執行 resolve() 后,狀態變成 resolved
const p2 = new Promise((resolve, reject) => { setTimeout(() => { resolve() }) }) // 執行 reject() 后,狀態變成 rejected
const p3 = new Promise((resolve, reject) => { setTimeout(() => { reject() }) })

 

2.狀態的表現和變化:

(1)pending狀態,不會觸發then和catch

(2)resolved狀態,會觸發后續的then回調函數

(3)rejected狀態,會觸發后續的catch回調函數

// 直接返回一個 resolved 狀態
Promise.resolve(100) // 直接返回一個 rejected 狀態
Promise.reject('some error')

 

3.then和catch對狀態的影響:

(1)then正常情況下返回resolved,里面有報錯則返回rejected

(2)catch正常情況下返回resolved,里面有報錯則返回rejected

// then() 一般正常返回 resolved 狀態的 promise
Promise.resolve().then(() => { return 100 }) // then() 里拋出錯誤,會返回 rejected 狀態的 promise
Promise.resolve().then(() => { throw new Error('err') }) // catch() 不拋出錯誤,會返回 resolved 狀態的 promise
Promise.reject().catch(() => { console.error('catch some error') }) // catch() 拋出錯誤,會返回 rejected 狀態的 promise
Promise.reject().catch(() => { console.error('catch some error') throw new Error('err') })

 

五、promise題目:

// 第一題,答案是1、3
Promise.resolve().then(() => { console.log(1) }).catch(() => { console.log(2) }).then(() => { console.log(3) }) // 第二題,答案是1、2、3
Promise.resolve().then(() => { // 返回 rejected 狀態的 promise
    console.log(1) throw new Error('erro1') }).catch(() => { // 返回 resolved 狀態的 promise
    console.log(2) }).then(() => { console.log(3) }) // 第三題,答案是1、2
Promise.resolve().then(() => { // 返回 rejected 狀態的 promise
    console.log(1) throw new Error('erro1') }).catch(() => { // 返回 resolved 狀態的 promise
    console.log(2) }).catch(() => { console.log(3) })

 

六、async/await:

1.背景:

(1)異步回調的callback hell

(2)Promise then catch鏈式調用,但也是基於回調函數

(3)async/await是同步語法,消滅回調函數

 

2.基本使用:

function loadImg(src) { const promise = new Promise((resolve, reject) => { const img = document.createElement('img') img.onload = () => { resolve(img) } img.onerror = () => { reject(new Error(`圖片加載失敗 ${src}`)) } img.src = src }) return promise } async function loadImg1() { const src1 = 'http://www.imooc.com/static/img/index/logo_new.png' const img1 = await loadImg(src1) return img1 } async function loadImg2() { const src2 = 'https://avatars3.githubusercontent.com/u/9583120' const img2 = await loadImg(src2) return img2 } (async function () { // 注意:await 必須放在 async 函數中,否則會報錯
    try { // 加載第一張圖片
        const img1 = await loadImg1() console.log(img1) // 加載第二張圖片
        const img2 = await loadImg2() console.log(img2) } catch (ex) { console.error(ex) } })()

 

3.async/await和Promise的關系:async/await可以消滅異步回調,但它和Promise並不互斥,兩者相輔相成

(1)執行async函數,返回的是Promise對象(如果函數內沒返回Promise對象,或者直接返回一個數值,則自動封裝成Promise對象)

(2)await相當於Promise的then

  1)基本原則:
    await 后面跟 Promise 對象:會阻斷后續代碼,等待狀態變為 resolved ,才獲取結果並繼續執行
    await 后續跟非 Promise 對象:會直接返回
  2)詳細使用:

    A.可以聲明一個變量接收函數的返回值:

      

      這里的data2接收了fn1的返回值

    B.await后面可以跟Promise對象、數值、一個async函數的返回值(async函數的返回值相當於Promise對象):

      

    C.await后面跟rejected的Promise對象,則不會執行,所以要用try...catch捕獲:

!(async function () { const p3 = Promise.reject('some err') const res = await p3 console.log(res) // 不會執行,因為await相當於then
})()

    D.await是同步寫法,但本質還是異步調用。只要遇到了await,后面的代碼都相當於放在 callback 里: 

async function async1 () { console.log('async1 start') await async2() console.log('async1 end') // 關鍵在這一步,它相當於放在 callback 中,最后執行
} async function async2 () { console.log('async2') } console.log('script start') async1() console.log('script end')

      

 

(3)用try...catch可捕獲異常,代替了Promise的catch

!(async function () { const p4 = Promise.reject('some err') try { const res = await p4 console.log(res) } catch (ex) { console.error(ex) } })()

  用try...catch捕獲異常使語法更加標准化(像其他語言一樣)

 

4.總結:

(1)async函數封裝了Promise

(2)await相當於Promise的then,處理Promise成功的情況

(3)要用try...catch處理Promise失敗的情況

 

七、async/await的本質:

1.async/await可以消滅異步回調

2.JavaScript還是單線程,還是得有異步,還是得基於事件循環(event loop)

3.async/await只是語法糖,只是從語法層面解決了異步回調

 

八、async/await題目:

1.第一題,答案:a是一個promise對象,b是100,因為async函數返回一個promise,而await相當於promise里面的then

 

2.第二題,答案:先打印start,然后a是100,b是200,執行到打印c會報錯,然后后面的代碼都不會執行了,因為await相當於then,只執行resolved,而這里是rejected,需要try..catch來執行

 

3.第三題,答案:依次打印script start、async1 start、async2、promise1、script end、async1 end、promise2、setTimeout,原因:

(1)setTimeout是宏任務

(2)await后面的都作為回調內容,是微任務

(3)初始化promise時,傳入的函數會立刻被執行

(4)then后面的回調是微任務

  

 

4.第四題(請使用Promise.all並行請求數據):

const getInfo = async(qq, callback) => { let baseInfo let payInfo try { let uidData = await axios.get('http://test.com/getUid', { params: { qq } }) if(uidData.ret === 0) { let uid = uidData.uid let [baseInfoData, payInfoData] = await Promise.all([ axios.get('http://test.com/getBaseInfo', { params: { uid } }), axios.get('http://test.com/getPayInfo', { params: { uid } }) ]) if(baseInfoData.ret === 0) { baseInfo = baseInfoData.info } else { baseInfo = {} } if(payInfoData.ret === 0) { payInfo = payInfoData.info } else { payInfo = {} } callback(Object.assign({}, baseInfo, payInfo)) } else { callback({}) } } catch(err) { throwError(err) } } getInfo(123456, function(data) { console.log(data) })

 


免責聲明!

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



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