js回調(diào)與異步編程

回調(diào)與異步編程

一、回調(diào)函數(shù)的使用場景

  1. 異步編程。
  2. 事件監(jiān)聽、處理。
  3. setTimeout、setInterval方法。
  4. 通用功能,簡化邏輯。

二、異步編程的4種方法

  1. 回調(diào)函數(shù)。
  2. 事件監(jiān)聽。
  3. 發(fā)布訂閱。
  4. Promise對象。

回調(diào)函數(shù)是一段可執(zhí)行的代碼段,它作為一個參數(shù)傳遞給其他的代碼,其作用是在需要的時候方便調(diào)用這段代碼。

fn1(fn2)
function fn1 () {
  // to do...
  fn2()
}

function fn2 () {
  // to do...
}

說到異步編程,那么就有必要了解js的事件循環(huán)機制Event Loop

image.png

1. 棧和隊列

image.png

棧: 后進先出(LIFO-last in first out):最后插入的元素最先出來。

隊列:先進先出(FIFO-first in first out):最先插入的元素最先出來。

2. 宏任務(wù)和微任務(wù)(瀏覽器)

宏隊列,macrotask。一些異步任務(wù)的回調(diào)會依次進入macro task queue,等待后續(xù)被調(diào)用:

  • setTimeout和setInterval

  • requestAnimationFrame

  • I/O

  • UI rendering

微隊列,microtask。 另一些異步任務(wù)的回調(diào)會依次進入micro task queue,等待后續(xù)被調(diào)用:

  • Promise.then

  • Object.observe

  • MutationObserver

執(zhí)行順序:

  1. 執(zhí)行全局Script同步代碼,這些同步代碼有一些是同步語句,有一些是異步語句(比如setTimeout等),遇到異步代碼根據(jù)上述任務(wù)劃分到對應(yīng)隊列中;

  2. 全局Script代碼執(zhí)行完畢后,調(diào)用棧Stack會清空;

  3. 從微隊列microtask queue中取出位于隊首的回調(diào)任務(wù),放入調(diào)用棧Stack中執(zhí)行,執(zhí)行完后microtask queue長度減1;

  4. 繼續(xù)取出位于隊首的任務(wù),放入調(diào)用棧Stack中執(zhí)行,以此類推,直到直到把microtask queue中的所有任務(wù)都執(zhí)行完畢。(即清空微任務(wù)隊列,注意:如果在執(zhí)行microtask的過程中,又產(chǎn)生了microtask,那么會加入到隊列的末尾,也會在這個周期被調(diào)用執(zhí)行)

  5. microtask queue中的所有任務(wù)都執(zhí)行完畢,此時microtask queue為空隊列,調(diào)用棧Stack也為空;

  6. 取出宏隊列macrotask queue中位于隊首的任務(wù),放入Stack中執(zhí)行;

  7. 執(zhí)行完畢后,調(diào)用棧Stack為空;

  8. 重復(fù)第3-7個步驟;

  9. ...

簡單來說,執(zhí)行主線程同步代碼遇到異步任務(wù)掛起劃分到對應(yīng)任務(wù)隊列,主線程同步代碼執(zhí)行完畢后,清空微任務(wù)隊列,此時微任務(wù)清空,執(zhí)行棧清空,開始執(zhí)行宏任務(wù),執(zhí)行完一個宏任務(wù)后查看微任務(wù)隊列并執(zhí)行清空,之后繼續(xù)執(zhí)行宏任務(wù)依次循環(huán)。

概念性的東西就這么多,來看幾個示例代碼,測試一下你是否掌握了:

console.log(1)

setTimeout(() => {
  console.log(2)
  Promise.resolve().then(() => {
    console.log(3)
  })
})

new Promise((resolve, reject) => {
  console.log(4)
  resolve(5)
}).then(data => {
  console.log(data)
  return 6
}).then(data => {
  console.log(data)
})

setTimeout(() => {
  console.log(7)
  Promise.resolve().then(() => {
    console.log(8)
  })
})

console.log(9)

1 4 9 5 6 2 3 7 8

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容