博客 / 詳情

返回

一字一句的讓你徹底掌握JavaScript中的回調函數

摘要:本文將會解釋回調函數的概念,同時幫你區分兩種回調:同步和異步。

原文鏈接:https://segmentfault.com/a/1190000038869766

回調函數是每個前端程序員都應該知道的概念之一。回調可用於數組、計時器函數、promise、事件處理中。

本文將會解釋回調函數的概念,同時幫你區分兩種回調:同步和異步。

回調函數

首先寫一個向人打招呼的函數。

只需要創建一個接受 name 參數的函數 greet(name)。這個函數應返回打招呼的消息:

如果向很多人打招呼該怎麼辦?可以用特殊的數組方法 array.map() 可以實現:

persons.map(greet) 獲取 persons 數組的所有元素,並分別用每個元素作為調用參數來調用 greet() 函數: `greet('Cristina'), greet('Ana')

有意思的是 persons.map(greet) 方法可以接受 greet() 函數作為參數。這樣 greet() 就成了回調函數

persons.map(greet) 是用另一個函數作為參數的函數,因此被稱為高階函數

回調函數

作為

高階函數

的參數,高階函數通過調用回調函數來執行操作。

重要的是高階函數負責調用回調,併為其提供正確的參數。

在前面的例子中,高階函數 persons.map(greet) 負責調用 greet() 函數,並分別把數組中所有的元素 'Cristina'Ana ' 作為參數。

這就為識別回調提供了一條簡單的規則。如果你定義了一個函數,並將其作參數提供給另一個函數的話,那麼這就創建了一個回調。

你可以自己編寫使用回調的高階函數。下面是 array.map() 方法的等效版本:

map(array, callback) 是一個高階函數,因為它用回調函數作為參數,然後在其主體內部調用該回調函數:callback(item)

注意,常規函數(用關鍵字 function 定義)或箭頭函數(用粗箭頭 => 定義)同樣可以作為回調使用。

同步回調

回調的調用方式有兩種:同步異步回調。

同步回調是“阻塞”的:高階函數直到回調函數完成後才繼續執行。

例如,調用 map()greet() 函數。

其中 greet() 是同步回調。

同步回調的步驟:

  1. 高階函數開始執行:'map() starts'
  2. 回調函數執行:'greet() called'
  3. .最後高階函數完成它自己的執行過程:'map() completed'

同步回調的例子

許多原生 JavaScript 類型的方法都使用同步回調。

最常用的是 array 的方法,例如: array.map(callback), array.forEach(callback), array.find(callback), array.filter(callback), array.reduce(callback, init)

字符串類型的 string.replace(callback) 方法也能接受同步執行的回調:

異步回調

異步回調是“非阻塞的”:高階函數無需等待回調完成即可完成其執行。高階函數可確保稍後在特定事件上執行回調。

在以下的例子中,later() 函數的執行延遲了 2 秒:

later() 是一個異步回調,因為 setTimeout(later`,`2000) 啓動並完成了執行,但是 later() 在 2 秒後執行。

異步調用回調的步驟:

  1. 高階函數開始執行:'setTimeout()starts'
  2. 高階函數完成其執行: 'setTimeout() completed'
  3. 回調函數在 2 秒鐘後執行: 'later() called'

異步回調的例子

計時器函數異步調用回調:

DOM 事件偵聽器還異步調用事件處理函數(回調函數的子類型):

異步回調函數與異步函數

在函數定義之前加上特殊關鍵字 async 會創建一個異步函數:

fetchUserNames() 是異步的,因為它以 async 為前綴。函數 await fetch('https://api.github.com/users?per_page=5') 從 GitHub 上獲取前5個用户 。然後從響應對象中提取 JSON 數據:await resp.json()

異步函數是 promise 之上的語法糖。當遇到表達式 await <promise> (調用 fetch() 會返回一個promise)時,異步函數會暫停執行,直到 promise 被解決。

異步回調函數和異步函數是不同的兩個術語。

異步回調函數由高階函數以非阻塞方式執行。但是異步函數在等待 promise(await <promise>)解析時會暫停執行。

但是你可以把異步函數用作異步回調!

讓我們把異步函數 fetch UserNames() 設為異步回調,只需單擊按鈕即可調用:

總結

回調是一個可以作為參數傳給另一個函數(高階函數)執行的函數。

回調函數有兩種:同步和異步。

同步回調是阻塞的。

異步回調是非阻塞的。

最後考考你:setTimeout(callback`,`0) 執行 callback 時是同步還是異步的?

user avatar docker_app 頭像 hellolvs 頭像 wangyaxi 頭像 joytime 頭像 beilee 頭像 notrynosuccess 頭像 643104191 頭像 hailongwang_od 頭像 bianchengshijie 頭像
9 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.