JavaScript:什麼是回調?

翻譯練習javascript

原博客地址:JavaScript: What the heck is a Callback?java

在6分鐘內經過簡單的例子學習和理解回調的基本原理。服務器

什麼是回調?

簡單地說:回調就是一個在另外一個函數執行完成後再去執行的函數--所以得名回調。app

複雜點講:在JavaScript中,函數是對象。所以,函數能夠把其餘函數當作參數,也能夠被其餘函數返回。這樣作的函數稱爲高階函數。任何被當作參數傳遞的函數都叫回調函數。函數

上面已經講了不少,讓咱們經過一些例子把這些去細化一下。學習

爲何咱們須要回調?

有一條很是重要的緣由:JavaScript是一門事件驅動的語言。這意味着,JavaScript在監聽其餘事件的同時會繼續執行,而不是在繼續執行以前去等待響應。翻譯

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

正如你指望的那樣,函數first會首先執行,函數second會接着執行--控制檯打印以下:code

// 1
// 2

目前看來一切良好。對象

可是,若是函數first包含一些不會當即執行的代碼會發生什麼呢?好比說,一個API請求,咱們必須去發送請求而後等待響應嗎?爲了模擬這種動做,咱們使用setTimeout--在JavaScript中,這個函數將會在設定的一段時間後去調用一個函數。咱們來把咱們的函數延遲500ms去模擬一個API請求。咱們的新代碼像下面這樣:教程

function first(){
  // Simulate a code delay
  setTimeout( function(){
    console.log(1);
  }, 500 );
}
function second(){
  console.log(2);
}
first();
second();

如今你理不理解setTimeout()怎麼工做的並不重要。如今最重要的是,你看咱們把console.log(1);移動到500ms的延時中。那麼,咱們如今執行代碼會發生什麼呢?

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.

如今,讓咱們來添加回調--做爲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 做爲參數傳給了它。

現實世界的例子

上週我發佈了一篇文章,這篇文章中代碼運行的惟一緣由就是Twitters API。當你對一個API發起請求時,你必須等到它響應才能對相應進行操做。這是一個現實生活中關於回調的完美例子。下面是這個請求的代碼:

T.get('search/tweets', params, function(err, data, response) {
  if(!err){
    // This is where the magic will happen
  } else {
    console.log(err);
  }
})
  • T.get僅僅表示咱們在向Twitter發起一個get請求。
  • search/tweets請求中有三個參數,分別是:請求的路由、查詢的參數param和咱們的回調--一個匿名函數。

回調在這裏很重要,由於在運行到後面的代碼以前,咱們須要先從服務器獲取到響應。咱們不知道在咱們講參數經過get請求發送到search/tweets 後咱們的API請求成功與否,咱們只能等着。一旦Twitter作出響應,咱們的回調函數就會被調用。Twitter要麼返回一個錯誤信息給咱們,或者返回響應對象給咱們。在咱們的回調函數中,咱們能夠經過if()語句去肯定咱們的請求是成功了仍是失敗了,而後相應地對新數據作出處理。

你作到了

幹得不錯。理想狀況下,你如今已經理解了什麼是回調還有它是怎麼工做的。這僅僅是回調的冰山一角,還有不少你須要去學習。我每週會發布了一些文章/教程,若是你想被加入到個人once-weekly郵箱列表,在這裏了輸入你的郵箱吧。

相關文章
相關標籤/搜索