[譯] JavaScript:回調是什麼鬼?


配合簡單的示例,用短短 6 分鐘學習和理解回調的基本知識。javascript

回調  —— 題圖來自 unsplash前端

回調是什麼?

簡單講: 回調是指在另外一個函數執行完成以後被調用的函數  ——  所以得名「回調」。java

稍複雜地講: 在 JavaScript 中,函數也是對象。所以,函數能夠傳入函數做爲參數,也能夠被其餘函數返回。這樣的函數稱爲高階函數。被做爲參數傳入的函數就叫作回調函數node

^ 這聽起來有點囉唆,讓咱們來看一些例子來簡化一下。react

爲何咱們須要回調?

有一個很是重要的緣由 —— JavaScript 是事件驅動的語言。這意味着,JavaScript 不會由於要等待一個響應而中止當前運行,而是在監聽其餘事件時繼續執行。來看一個基本的例子:android

function first(){
  console.log(1);
}

function second(){
  console.log(2);
}

first();
second();複製代碼

正如你所料,first 函數首先被執行,隨後 second 被執行 —— 控制檯輸出下面內容:ios

// 1
// 2複製代碼

一切都如此美好。git

但若是函數 first 包含某種不能當即執行的代碼會如何呢?例如咱們必須發送請求而後等待響應的 API 請求?爲了模擬這種情況,咱們將使用 setTimeout,它是一個在一段時間以後調用函數的 JavaScript 函數。咱們將函數延遲 500 毫秒來模擬一個 API 請求,新代碼長這樣:github

function first(){
// 模擬代碼延遲
  setTimeout( function(){
console.log(1);
  }, 500 );
}

function second(){
  console.log(2);
}

first();
second();複製代碼

如今理解 setTimeout() 是如何工做的並不重要,重要的是你看到了咱們已經把 console.log(1); 移動到了 500 秒延遲函數內部。那麼如今調用函數會發生什麼呢?後端

first();
second();

// 2
// 1複製代碼

即便咱們首先調用了 first() 函數,咱們記錄的輸出結果卻在 second() 函數以後。

這不是 JavaScript 沒有按照咱們想要的順序執行函數的問題,而是 JavaScript 在繼續向下執行 second() 以前沒有等待 first() 響應的問題。

因此爲何給你看這個?由於你不能一個接一個地調用函數並但願它們按照正確的順序執行。回調正是確保一段代碼執行完畢以後再執行另外一段代碼的方式。

建立一個回調

好了,說了這麼多,讓咱們建立一個回調!

首先,打開你的 Chrome 開發者工具(Windows: Ctrl + Shift + J)(Mac: Cmd + Option + J),在控制檯輸入下面的函數聲明:

function doHomework(subject) {
  alert(`Starting my ${subject} homework.`);
}複製代碼

上面,咱們已經建立了 doHomework 函數。咱們的函數攜帶一個變量,是咱們正在研究的課題。在控制檯輸入下面內容調用你的函數:

doHomework('math');

// Alerts: Starting my math homework.複製代碼

如今把咱們的回調加進來,咱們傳入 callback 做爲 doHomework() 的最後一個參數。這個回調函數是咱們定義在接下來要調用的 doHomework() 函數的第二個參數。

function doHomework(subject**, callback**) {
  alert(`Starting my ${subject} homework.`);
**callback();**
}

doHomework('math'**, function() {
  alert('Finished my homework');
}**);複製代碼

如你所見,若是你將上面的代碼輸入控制檯,你將依次獲得兩個警告:第一個是「starting homework」,接着是「finished homework」。

可是你的回調函數並不老是必須定義在函數調用裏面,它們也能夠定義在你代碼中的其餘位置,好比這樣:

function doHomework(subject, callback) {
  alert(`Starting my ${subject} homework.`);
  callback();
}

function alertFinished(){
  alert('Finished my homework');
}

**doHomework('math', alertFinished);**複製代碼

這個例子的結果和以前的例子徹底一致。如你所見,咱們在 doHomework() 函數調用中傳入了 alertFinished 函數定義做爲參數!

實際應用案例

上週我發表了一篇關於如何用 38 行代碼構建一個 Twitter 機器人的文章。文中的代碼能夠實現的惟一緣由就是我使用了 Twitters API。當你向一個 API 發送請求,在你操做響應內容以前你必須等待這個響應。這是回調在實際應用中的絕佳案例。請求長這樣:

T.get('search/tweets', params, function(err, data, response) {
  if(!err){
    // 這裏是施展魔法之處
  } else {
    console.log(err);
  }
})複製代碼
  • T.get 僅僅意味着咱們將要向 Twitter 發送一個 get 請求
  • 這個請求中有三個參數:‘search/tweets’ 是請求的路徑,params 是搜索參數,隨後的一個匿名函數是咱們的回調。

回調在這裏很重要,由於在咱們的代碼繼續運行以前咱們須要等待一個來自服務端的響應。咱們並不知道 API 請求會成功仍是會失敗,因此經過 get 向 search/tweets 發送了請求參數之後,咱們要等待。一旦 Twitter 響應,咱們的回調函數就被調用。Twitter 要麼發送一個 err(error)對象,要麼發送一個 response 對象返回給咱們。在咱們的回調函數中咱們可使用 if() 語句來區分請求是否成功,而後相應地處理新數據。

你作到了

幹得漂亮!你如今(理想情況下)已經理解了回調是什麼,回調如何工做。這只是回調的冰山一角,記住學無止境啊!我每週都會更新一些文章/教程,若是你願意接收每週一次的推送,點擊這裏輸入你的郵箱訂閱吧!


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOSReact前端後端產品設計 等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃

相關文章
相關標籤/搜索