生活随笔
收集整理的這篇文章主要介紹了
(八)JS异步进阶,更深更广搞定JS异步【想要进大厂,更多异步的问题等着你】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
JS異步進階 提問 event loop JS如何執行 示例 總結event loop的過程 DOM事件和event loop promise進階 三種狀態 狀態的表現和變化 then和catch對狀態的影響(then和catch改變狀態) Promise總結 async/await async-await和Promise有什么關系 async/await是語法糖,異步的本質還是回調函數 for...of 微任務microTask和宏任務macroTask 宏任務和微任務 event loop和DOM渲染 宏任務和微任務的區別 從event loop解釋,為何微任務執行更早
之前講解JS異步,在于初階的應用 本章在于JS異步的原理和進階
提問
請描述event loop(事件循環/事件輪詢)的機制,可畫圖 什么是宏任務和微任務,兩者有什么區別 Promise有哪三種狀態?如何變化 promise then和catch的連接
Promise
. resolve ( ) . then ( ( ) => { console
. log ( 1 )
} ) . catch ( ( ) => { console
. log ( 2 )
} ) . then ( ( ) => { console
. log ( 3 )
} )
Promise
. resolve ( ) . then ( ( ) => { console
. log ( 1 ) throw new Error ( 'erro1' )
} ) . catch ( ( ) => { console
. log ( 2 )
} ) . then ( ( ) => { console
. log ( 3 )
} )
Promise
. resolve ( ) . then ( ( ) => { console
. log ( 1 ) throw new Error ( 'erro1' )
} ) . catch ( ( ) => { console
. log ( 2 )
} ) . catch ( ( ) => { console
. log ( 3 )
} )
async function fn ( ) { return 100
}
( async function ( ) { const a
= fn ( ) const b
= await fn ( )
} ) ( )
( async function ( ) { console
. log ( 'start' ) const a
= await 100 console
. log ( 'a' , a
) const b
= await Promise
. resolve ( 200 ) console
. log ( 'b' , b
) const c
= await Promise
. reject ( 300 ) console
. log ( 'c' , c
) console
. log ( 'end' )
} ) ( )
console
. log ( 100 )
setTimeout ( ( ) => { console
. log ( 200 )
} )
Promise
. resolve ( ) . then ( ( ) => { console
. log ( 300 )
} )
console
. log ( 400 )
async function async1 ( ) { console
. log ( 'async1 start' ) await async2 ( ) console
. log ( 'async1 end' )
} async function async2 ( ) { console
. log ( 'async2' )
} console
. log ( 'script start' ) setTimeout ( function ( ) { console
. log ( 'setTimeout' )
} , 0 ) async1 ( )
new Promise ( function ( resolve
) { console
. log ( 'promise1' ) resolve ( )
} ) . then ( function ( ) { console
. log ( 'promise2' )
} ) console
. log ( 'script end' )
event loop
JS是單線程運行的 異步要基于回調來實現 event loop就是異步回調的實現原理
JS如何執行
從前到后,一行一行執行 如果某一行執行報錯,則停止下面代碼的執行 先把同步代碼執行完,再執行異步
示例
console
. log ( 'Hi' ) setTimeout ( function cb1 ( ) { console
. log ( 'cb1' )
} , 5000 ) console
. log ( 'Bye' )
總結event loop的過程
同步代碼,一行一行放在Call Stack調用棧執行 遇到異步,會先“記錄”下,等待時機(定時、網絡請求等) 時機到了,就會移動到Callback Queue 如Call Stack為空(即同步代碼執行完)Event Loop開始工作 輪詢查找Callback Queue,如有則移動到Call Stack執行 然后繼續輪詢查找(永動機一樣)
DOM事件和event loop
JS是單線程的 異步(setTimeOut,ajax等)使用回調,基于event loop Dom事件不是異步,但DOM事件也使用回調,基于event loop
< button id
= "btn1" > 提交
< / button
> < script
>
console
. log ( 'Hi' ) $ ( '#btn1' ) . click ( function ( e
) { console
. log ( 'button clicked' )
} ) console
. log ( 'Bye' )
< / script
>
promise進階
三種狀態
pending resolved rejected pending 》resolved 或 pending 》rejected 變化不可逆
const p1
= new Promise ( ( resolve
, reject
) => {
} )
console
. log ( 'p1' , p1
)
const p2
= new Promise ( ( resolve
, reject
) => { setTimeout ( ( ) => { resolve ( ) } )
} )
console
. log ( 'p2' , p2
)
setTimeout ( ( ) => console
. log ( 'p2-setTimeout' , p2
) )
const p3
= new Promise ( ( resolve
, reject
) => { setTimeout ( ( ) => { reject ( ) } )
} )
console
. log ( 'p3' , p3
)
setTimeout ( ( ) => console
. log ( 'p3-setTimeout' , p3
) )
狀態的表現和變化
pending狀態,不會觸發then和catch resolved狀態,會觸發后續的then回調函數 rejected狀態,會觸發后續的catch回調函數
const p1
= Promise
. resolve ( 100 )
console
. log ( 'p1' , p1
)
const p2
= Promise
. reject ( 'err' )
console
. log ( 'p2' , p2
)
const p1
= Promise
. resolve ( 100 )
p1
. then ( data
=> { console
. log ( 'data' , data
)
} ) . catch ( err
=> { console
. error ( 'err' , err
)
} )
const p2
= Promise
. reject ( 'err' )
p2
. then ( data
=> { console
. log ( 'data2' , data
)
} ) . catch ( err
=> { console
. error ( 'err2' , err
)
} )
then和catch對狀態的影響(then和catch改變狀態)
then catch 會繼續返回 Promise ,此時可能會發生狀態變化!!!
then正常返回resolved,里面有報錯則返回rejected catch正常返回resolved,里面有報錯則返回rejected
const p1
= Promise
. resolve ( ) . then ( ( ) => { return 100
} )
console
. log ( 'p1' , p1
)
const p2
= Promise
. resolve ( ) . then ( ( ) => { throw new Error ( 'then error' )
} )
console
. log ( 'p2' , p2
)
const p1
= Promise
. resolve ( ) . then ( ( ) => { return 100
} )
console
. log ( 'p1' , p1
)
p1
. then ( ( ) => { console
. log ( '123' )
} )
const p2
= Promise
. resolve ( ) . then ( ( ) => { throw new Error ( 'then error' )
} )
console
. log ( 'p2' , p2
)
p2
. then ( ( ) => { console
. log ( '456' )
} ) . catch ( err
=> { console
. error ( 'err100' , err
)
} )
const p3
= Promise
. reject ( 'my error' ) . catch ( ( err
) => { console
. error ( 'err
)
} )
console
. log ( 'p3' , p3
)
p3
. then ( ( ) => { console
. log ( 100 )
} )
const p4
= Promise
. reject ( ( 'my error' ) . catch ( ( err
) => { throw new Error ( 'catch err' )
} )
console
. log ( 'p4' , p4
)
p4
. then ( ( ) => { console
. log ( 200 )
} ) . catch ( ( ) => { console
. error ( 'some err' )
} )
Promise
. resolve ( ) . then ( ( ) => { return 100
} )
Promise
. resolve ( ) . then ( ( ) => { throw new Error ( 'err' )
} )
Promise
. reject ( ) . catch ( ( ) => { console
. error ( 'catch some error' )
} )
Promise
. reject ( ) . catch ( ( ) => { console
. error ( 'catch some error' ) throw new Error ( 'err' )
} )
Promise
. resolve ( ) . then ( ( ) => { console
. log ( 1 )
} ) . catch ( ( ) => { console
. log ( 2 )
} ) . then ( ( ) => { console
. log ( 3 )
} )
Promise
. resolve ( ) . then ( ( ) => { console
. log ( 1 ) throw new Error ( 'erro1' )
} ) . catch ( ( ) => { console
. log ( 2 )
} ) . then ( ( ) => { console
. log ( 3 )
} )
Promise
. resolve ( ) . then ( ( ) => { console
. log ( 1 ) throw new Error ( 'erro1' )
} ) . catch ( ( ) => { console
. log ( 2 )
} ) . catch ( ( ) => { console
. log ( 3 )
} )
Promise總結
三種狀態,狀態的表現和變化 then和catch對狀態的影響 then和catch的鏈式調用
async/await
異步調用callback hell Promise then catch鏈式調用,但也是基于回調函數 async/await是同步語法實現異步,徹底消滅回調函數
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
}
const src1
= 'http://www.imooc.com/static/img/index/logo_new.png'
const src2
= 'https://avatars3.githubusercontent.com/u/9583120'
( async function ( ) { const img1
= await loadImg ( src1
) console
. log ( img1
) const img2
= await loadImg ( src2
) console
. log ( img2
)
} ) ( )
會報 因為src2后面沒加分號,和后面的()連在一起被當做函數,類似圖示alert也會彈出彈框,解決辦法:(async前面加!號
const src1
= 'http://www.imooc.com/static/img/index/logo_new.png'
const src2
= 'https://avatars3.githubusercontent.com/u/9583120'
! ( async function ( ) { const img1
= await loadImg ( src1
) console
. log ( img1
) const img2
= await loadImg ( src2
) console
. log ( img2
)
} ) ( )
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 ( ) { try { const img1
= await loadImg1 ( ) console
. log ( img1
) const img2
= await loadImg2 ( ) console
. log ( img2
) } catch ( ex ) { console
. error ( ex
) }
} ) ( )
async-await和Promise有什么關系
async/await是消滅異步回調的終極武器 但和Promise并不互斥 反而,兩者相輔相成 執行async函數,返回的是Promise對象,如果函數內沒返回 Promise ,則自動封裝成Promise對象
async function fn1 ( ) { return new Promise ( 200 )
}
const res1
= fn1 ( )
res1
. then ( data
=> { console
. log ( 'data' , data
) } ) async function fn2 ( ) { return 100
}
console
. log ( fn2 ( ) )
await 相當于Promise的then,await 后面可以加promise對象、值、async函數的執行結果
! ( async function ( ) { const p1
= Promise
. resolve ( 100 ) const data
= await p1 console
. log ( 'data' , data
)
} ) ( )
! ( async function ( ) { const data1
= await 400 console
. log ( 'data1' , data1
)
} ) ( )
! ( async function ( ) { const data2
= await fn1 ( ) console
. log ( 'data2' , data2
)
} ) ( ) ! ( async function ( ) { const p1
= new Promise ( ( ) => { } ) await p1console
. log ( 'p1' )
} ) ( )
! ( async function ( ) { const p4
= Promise
. reject ( 'some err' ) const res
= await p4 console
. log ( res
)
} ) ( )
try…catch可捕獲異常,代替了Promise的catch
! ( async function ( ) { const p4
= Promise
. reject ( 'some err' ) try { const res
= await p4console
. log ( res
) } catch ( ex ) { console
. error ( ex
) }
} ) ( )
async 封裝 Promise
await 處理 Promise 成功
try ... catch 處理 Promise 失敗
async/await是語法糖,異步的本質還是回調函數
async/await是消滅異步回調的終極武器 JS是單線程,還得是有異步,還得是基于event loop async/await只是一個語法糖,但這顆糖真香
async function async1 ( ) { console
. log ( 'async1 start' ) await async2 ( ) console
. log ( 'async1 end' )
} async function async2 ( ) { console
. log ( 'async2' )
} console
. log ( 'script start' )
async1 ( )
console
. log ( 'script end' )
async function async1 ( ) { console
. log ( 'async1 start' ) await async2 ( ) console
. log ( 'async1 end' ) await async3 ( ) console
. log ( 'async1 end 2' ) } async function async2 ( ) { console
. log ( 'async2' )
} async function async3 ( ) { console
. log ( 'async3' )
}
console
. log ( 'script start' )
async1 ( )
console
. log ( 'script end' )
for…of
for…in(以及forEach for) 是常規的同步遍歷 for…of常用于異步的遍歷
function multi ( num
) { return new Promise ( ( resolve
) => { setTimeout ( ( ) => { resolve ( num
* num
) } , 1000 ) } )
}
async function test2 ( ) { const nums
= [ 1 , 2 , 3 ] ; for ( let x
of nums
) { const res
= await multi ( x
) console
. log ( res
) }
}
test2 ( )
微任務microTask和宏任務macroTask
什么是宏任務,什么是微任務 event loop和DOM渲染 微任務和宏任務的區別
console
. log ( 100 )
setTimeout ( ( ) => { console
. log ( 200 )
} )
Promise
. resolve ( ) . then ( ( ) => { console
. log ( 300 )
} )
console
. log ( 400 )
宏任務和微任務
宏任務:setTimeout,setInterval,Ajax,DOM事件 微任務:Promise async/await 微任務執行時機比宏任務要早(先記住)
event loop和DOM渲染
再次回歸一遍event loop的過程 JS是單線程的,而且和DOM渲染共用一個線程 JS執行的時候,得留一些時機供DOM渲染 回顧event loop過程(增加DOM渲染時機)
1. 每次Call Stack清空(即每次輪詢結束),即同步任務執行完,或者說異步代碼推到Call Stack執行結束
2. 都是
DOM 重新渲染的機會,
DOM 結構如有改變則重新渲染,(不一定非得渲染,就是給一次
DOM 渲染的機會!!!)
3. 然后再去觸發下一次Event Loop
const $p1
= $ ( '<p>一段文字</p>' )
const $p2
= $ ( '<p>一段文字</p>' )
const $p3
= $ ( '<p>一段文字</p>' )
$ ( '#container' ) . append ( $p1
) . append ( $p2
) . append ( $p3
) console
. log ( 'length' , $ ( '#container' ) . children ( ) . length
)
alert ( '本次 call stack 結束,DOM 結構已更新,但尚未觸發渲染' )
Promise
. resolve ( ) . then ( ( ) => { console
. log ( 'length1' , $ ( '#container' ) . children ( ) . length
)
alert ( 'Promise then' )
} )
setTimeout ( ( ) => { console
. log ( 'length2' , $ ( '#container' ) . children ( ) . length
)
alert ( 'setTimeout' )
} )
宏任務和微任務的區別
宏任務:DOM渲染后觸發,如setTimeout 微任務:DOM渲染前觸發,如Promise
從event loop解釋,為何微任務執行更早
宏任務(瀏覽器規定的) 微任務(ES6語法規定的)
微任務:
ES 語法標準之內,
JS 引擎來統一處理。即,不用瀏覽器有任何關于,即可一次性處理完,更快更及時。
宏任務:
ES 語法沒有,
JS 引擎不處理,瀏覽器(或 nodejs)干預處理。
總結
以上是生活随笔 為你收集整理的(八)JS异步进阶,更深更广搞定JS异步【想要进大厂,更多异步的问题等着你】 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。