日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

(八)JS异步进阶,更深更广搞定JS异步【想要进大厂,更多异步的问题等着你】

發布時間:2023/12/31 javascript 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (八)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) }) // 1 3// 第二題 Promise.resolve().then(() => {console.log(1)throw new Error('erro1') }).catch(() => {console.log(2) }).then(() => {console.log(3) }) // 1 2 3// 第三題 Promise.resolve().then(() => {console.log(1)throw new Error('erro1') }).catch(() => {console.log(2) }).catch(() => { // 注意這里是 catchconsole.log(3) }) // 1 2
  • async/await 語法問題
async function fn() {return 100 } (async function () {const a = fn() // ?? // promise對象const b = await fn() // ?? // 100 })() (async function () {console.log('start')const a = await 100console.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') })() // 執行完畢,打印出那些內容?//start a,100 b,200
  • Promise 和 setTimeout 順序
console.log(100) setTimeout(() => {console.log(200) }) Promise.resolve().then(() => {console.log(300) }) console.log(400) // 100 400 300 200
  • async/await的執行順序問題
async function async1 () {console.log('async1 start') //2await async2() // 這一句會同步執行,返回 Promise ,其中的 `console.log('async2')` 也會同步執行console.log('async1 end') //6 await 后面的都作為回調內容---微任務 }async function async2 () {console.log('async2') //3 }console.log('script start') //1setTimeout(function () { // 異步,宏任務console.log('setTimeout') //8 }, 0)async1() // 初始化 promise 時,傳入的函數會立刻被執行 new Promise (function (resolve) {console.log('promise1') // 4 resolve() }).then (function () { // 異步,微任務console.log('promise2') //7 })console.log('script end') //5// 同步代碼執行完之后,屢一下現有的異步未執行的,按照順序 // 1. async1 函數中 await 后面的內容 —— 微任務 // 2. setTimeout —— 宏任務 // 3. then —— 微任務// 同步代碼執行完畢 (event loop - call stack 被清空) // 執行微任務 // (嘗試觸發DOM渲染) // 觸發Event Loop,執行宏任務

event loop

  • JS是單線程運行的
  • 異步要基于回調來實現
  • event loop就是異步回調的實現原理

JS如何執行

  • 從前到后,一行一行執行
  • 如果某一行執行報錯,則停止下面代碼的執行
  • 先把同步代碼執行完,再執行異步

示例

console.log('Hi')setTimeout(function cb1() {console.log('cb1') // cb 即 callback }, 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
//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
  • 變化不可逆
// 剛定義時,狀態默認為 pending const p1 = new Promise((resolve, reject) => { }) console.log('p1',p1) // pending// 執行 resolve() 后,狀態變成 resolved const p2 = new Promise((resolve, reject) => {setTimeout(() => {resolve()}) }) console.log('p2',p2) // pending - 開始打印時 setTimeout(() => console.log('p2-setTimeout',p2)) //resolved// 執行 reject() 后,狀態變成 rejected const p3 = new Promise((resolve, reject) => {setTimeout(() => {reject()}) }) console.log('p3',p3) // pending - 開始打印時 setTimeout(() => console.log('p3-setTimeout',p3)) //rejected

狀態的表現和變化

  • 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) //resolved //console.log('p1',p1) p1.then(data => {console.log('data',data) }).catch(err => {console.error('err',err) }) const p2 = Promise.reject('err') //rejected //console.log('p2',p2) 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) //resolved const p2 = Promise.resolve().then(() => {throw new Error('then error') }) console.log('p2',p2) //rejected

const p1 = Promise.resolve().then(() => {return 100 }) console.log('p1',p1) //resolved 觸發后續then回調 p1.then(() => {console.log('123') }) const p2 = Promise.resolve().then(() => {throw new Error('then error') }) console.log('p2',p2) //rejected 觸發后續catch回調 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) //resolved 注意!觸發then函數 p3.then(() => {console.log(100) }) const p4 = Promise.reject(('my error').catch((err) => {throw new Error('catch err') }) console.log('p4',p4) //rejected 觸發后續catch回調 p4.then(() => {console.log(200) }).catch(()=> {console.error('some err') })

// 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.resolve().then(() => {console.log(1) //1 }).catch(() => {console.log(2) }).then(() => {console.log(3) //3 })// 第二題 Promise.resolve().then(() => { // 返回 rejected 狀態的 promiseconsole.log(1) //1throw new Error('erro1') }).catch(() => { // 返回 resolved 狀態的 promiseconsole.log(2) //2 }).then(() => {console.log(3) //3 })// 第三題 Promise.resolve().then(() => { // 返回 rejected 狀態的 promiseconsole.log(1) //1throw new Error('erro1') }).catch(() => { // 返回 resolved 狀態的 promiseconsole.log(2) //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 () {// 注意:await 必須放在 async 函數中,否則會報錯// 加載第一張圖片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 () {// 注意:await 必須放在 async 函數中,否則會報錯// 加載第一張圖片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 () {// 注意:await 必須放在 async 函數中,否則會報錯try {// 加載第一張圖片const img1 = await loadImg1() //await后面不僅可以加promise對象也可以加async函數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()//執行async函數,返回的是一個Promise對象 res1.then(data => {console.log('data',data)}) //200async function fn2() {return 100 // 相當于 Promise.resolve(100) } console.log( fn2() ) //Promise對象
  • await 相當于Promise的then,await 后面可以加promise對象、值、async函數的執行結果
// await 后面跟 Promise 對象:會阻斷后續代碼,等待狀態變為 resolved ,才獲取結果并繼續執行 // await 后續跟非 Promise 對象:會直接返回 !(async function () {const p1 = Promise.resolve(100)const data = await p1 // await 相當于Promise的thenconsole.log('data',data) // 100 })() !(async function () {const data1 = await 400 // await Promise.resolve(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') //rejected狀態const res = await p4 // await -> thenconsole.log(res) // 不會執行 })()
  • try…catch可捕獲異常,代替了Promise的catch
!(async function () {const p4 = Promise.reject('some err') //rejected狀態try {const res = await p4console.log(res)} catch (ex) {console.error(ex) // try...catch 相當于 promise catch} })() //總結 async 封裝 Promise await 處理 Promise 成功 try...catch 處理 Promise 失敗

async/await是語法糖,異步的本質還是回調函數

  • async/await是消滅異步回調的終極武器
  • JS是單線程,還得是有異步,還得是基于event loop
  • async/await只是一個語法糖,但這顆糖真香
//只要遇到了 await ,后面的代碼都相當于放在 callback 里 async function async1 () {console.log('async1 start') // 2await async2() //undefined// await 的后面都可以看做是calllback里的內容,即異步// 類似,event loop,setTimeout(cb1)// setTimeout(function() { console.log('async1 end') })// Promise.resolve().then(() => { console.log('async1 end') } ) //微任務/宏任務console.log('async1 end') // 5 關鍵在這一步,它相當于放在 callback 中,最后執行 }async function async2 () {console.log('async2') // 3 }console.log('script start') //1 async1() //立馬執行async1函數體 console.log('script end') //4 // 同步代碼已經執行完(event loop) async function async1 () {console.log('async1 start') // 2await async2()// 下面三行都是異步回調 callback的內容console.log('async1 end') // 5await async3()console.log('async1 end 2')} //7async function async2 () {console.log('async2') // 3 }async function async3 () {console.log('async3') // 6 } console.log('script start') //1 async1() console.log('script end') //4 // 同步代碼已經執行完(event loop)

for…of

  • for…in(以及forEach for) 是常規的同步遍歷
  • for…of常用于異步的遍歷
// 定時算乘法 function multi(num) {return new Promise((resolve) => {setTimeout(() => {resolve(num * num)}, 1000)}) }// // 使用 forEach ,是 1s 之后打印出所有結果,即 3 個值是一起被計算出來的 // function test1 () { // const nums = [1, 2, 3]; // nums.forEach(async x => { // const res = await multi(x); // console.log(res); // }) // } // test1();// 使用 for...of ,可以讓計算挨個串行執行 async function test2 () {const nums = [1, 2, 3];for (let x of nums) {// 在 for...of 循環體的內部,遇到 await 會挨個串行計算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) // 100 400 300 200

宏任務和微任務

  • 宏任務: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 結構已更新,但尚未觸發渲染') // (alert 會阻斷 js 執行,也會阻斷 DOM 渲染,便于查看效果) // 到此,即本次 call stack 結束后(同步任務都執行完了),瀏覽器會自動觸發渲染,不用代碼干預// 微任務:DOM渲染前觸發 Promise.resolve().then(() => {console.log('length1',$('#container').children().length) //3 alert('Promise then') //DOM渲染了嗎?NO }) // 宏任務:DOM渲染后觸發 setTimeout(() => {console.log('length2',$('#container').children().length) //3 alert('setTimeout') //DOM渲染了嗎?yes })

宏任務和微任務的區別

  • 宏任務:DOM渲染后觸發,如setTimeout
  • 微任務:DOM渲染前觸發,如Promise

從event loop解釋,為何微任務執行更早

  • 宏任務(瀏覽器規定的)

  • 微任務(ES6語法規定的)

微任務:ES 語法標準之內,JS 引擎來統一處理。即,不用瀏覽器有任何關于,即可一次性處理完,更快更及時。 宏任務:ES 語法沒有,JS 引擎不處理,瀏覽器(或 nodejs)干預處理。

總結

以上是生活随笔為你收集整理的(八)JS异步进阶,更深更广搞定JS异步【想要进大厂,更多异步的问题等着你】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。