2016-05-24 83 views
0

當涉及到JavaScript回調時,我非常困惑......特別是當試圖在同一時間學習節點時。 您知道,我理解將函數作爲參數傳遞給另一個函數的概念,但我最主要困惑的是預製模塊「接受」回調函數。瞭解回調

例如一個簡單的請求看起來像這樣:

var request = require('request'); 
var url = 'http://www.google.com'; 

request.get(url, function(error, response, body) { 

    if(error){ 
     console.log('This request resulted in an error', error); 
    } 
    console.log(body); 
}); 

此get方法接受一個URL和一個回調。 誰定義回調被接受?具體方法的開發者? 此外,我們在函數(錯誤,響應和正文)中傳遞的3個參數...請求模塊如何知道使用返回的數據填充這些變量?

+1

imo,用JavaScript瞭解'回調'或關閉。通過node.js,儘快瞭解'promises'。並且只能在非常有限的情況下使用回調。或命令鏈可能有用?也許有趣? http://stackabuse.com/avoiding-callback-hell-in-node-js/ –

+0

@Query - 如果下面的答案之一回答了您的問題,請通過點擊最佳答案左側的綠色複選標記來指出。如果不是,那麼請對每個答案評論它尚未回答的內容。 – jfriend00

回答

1

想象get實現或多或少像

function get(url, callback) { 
    var response = they somehow retrieve the response; 
    var body = they somehow parse the body; 
    var error = ...; 

    // they call you back using your callback 
    callback(error, response, body); 
} 

如何將這些值計算是無關緊要的(這是他們的實際工作),但是他們只是給你回電話假設你的函數實際上接受給定的順序三個參數(如果不是,你只是得到一個運行時錯誤)。

從這個意義上說,它們也可以「接受」你的回調......好吧,把它回叫:)不必擔心參數的數量,因爲Javascript非常「寬容」 - 可以使用任何方法調用方法參數數量,包括比函數期望的參數更少或更多的參數。

以此爲一個例子:

// they provide 3 arguments 
function get(callback) { 
    callback(0, 1, 2); 
} 

// but you seem to expect none 
get(function() { 
}); 

get假定回調接受三個參數我過去,理應不接受參數的方法。這工作,雖然三個參數,012沒有綁定到任何正式的回調參數(你不能直接引用它們),他們在那裏的arguments對象,數組狀結構:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments

再舉一個例子

function get(callback) { 
    callback(0, 1, 2); 
} 

get(function(a,b,c,d,e) { 
}); 

這一次,我經過回調似乎期待參數比調用者提供在這裏,仍然沒有問題。參數綁定連續呼叫參數,a將獲得0,b將獲得1,c將獲得2和de將得到undefined內部的回調正文。

這兩個例子都表明調用者並不在意你的回調是如何定義的,它的參數個數是否符合期望值。在任何不匹配的情況下,會發生什麼最壞的是一個運行時錯誤:

function get(callback) { 
    callback(0, 1, 2); 
} 

get(1); 

// Uncaught TypeError: callback is not a function 
1

This get method accepts a url and a callback. Who defines that a callback is accepted? The developer of the specific method?

是。作者request.get()明確定義它期望並使用「回調」功能。

您可以定義自己的函數來接受回調函數,當它們依賴於其他異步函數時尤其有用,例如setTimeout()就是一個簡單的例子。

function delay(value, callback) { 
    setTimeout(function() { 
     // this statement defines the arguments given to the callback 
     // it specifies that only one is given, which is the `value` 
     callback(value); 
    }, 1000); 
} 

delay('foo', function (value) { // named to match the argument `delay` provides 
    console.log(value); 
}); 

Also, the 3 parameters that we pass within the function (error, response, and body)... how does the request module know to populate these variables with data on return?

的參數給出,並且它們的順序是request的定義的一部分,相同delay()上述限定(value)將是其callback參數(一個或多個)。

提供回調時,參數只給出您自己使用的參數名稱。它們對主函數(request.get()delay()等)的行爲沒有影響。

即使沒有命名任何參數,request.get()仍通過相同的3個參數以相同的順序給回調:

request.get(url, function() { // no named parameters 
    var error = arguments[0]; // still the 1st argument at `0` index 
    var body = arguments[2]; // still the 3rd argument at `2` index 

    if(error){ 
     console.log('This request resulted in an error', error); 
    } 
    console.log(body); 
}); 
1

函數/方法的設計者決定什麼樣的參數會接受和處理。所以,如果一個函數接受回調作爲參數,那麼函數的設計和實現就決定了它,並且會在適當的時候調用回調函數。

它也是函數/方法的實現者,它決定在調用時將傳遞給回調函數的參數。令許多人困惑的是,函數的調用者定義了將由主函數/方法調用的回調函數本身。但是回調函數的參數必須聲明爲與主函數/方法將傳遞給回調的內容相匹配。定義回調時爲參數提供的標籤僅僅是用於編程方便的標籤(作爲按名稱引用參數的一種方式)。在回調函數中如何定義回調參數與實際傳遞給回調函數的內容無關 - 這一切都由調用回調的函數/方法決定。所以,當你使用request.get()時,使用它的合同是它接受一個回調,該回調應該被聲明爲具有參數(error, response, body),因爲它將被調用。現在,如果你不打算使用它們(它們仍然會在那裏,但你不會有一個方便的名稱來引用它們),那麼在最後拋棄一些論據是可以的,但是你不能因爲命令很重要,所以在你打算使用任何打算使用之前,請將論點放開。

Who defines that a callback is accepted? The developer of the specific method?

是的,函數/方法的開發者決定是否接受回調函數。

Also, the 3 parameters that we pass within the function (error, response, and body)... how does the request module know to populate these variables with data on return?

request.get()方法被編程爲三個參數(error, response, body)傳遞給它的回調,這就是它會通過。不管回調本身如何實際聲明,request.get()將按順序傳遞這三個參數。所以,讓很多人困惑的是函數/方法的調用者自己創建了回調函數,並且爲它定義了參數。那麼,不是真的。回調的創建者必須創建一個回調,匹配函數/方法期望的契約。如果它與合約不匹配,那麼回調可能無法正常運作,因爲它會對傳遞的內容感到困惑。真的,這裏的合同是回調的第一個參數是error值,如果該值不是真的,那麼接下來的兩個參數將是responsebody。您的回叫必須與該聯繫人匹配才能正確使用這些參數。因爲Javascript沒有嚴格的類型,如果你錯誤地聲明你的回調,它不會是一個運行時錯誤,但是你對這些參數的訪問可能是錯誤的 - 導致錯誤的工作。

例如,如果你宣佈你的回調是:

function myCallback(response, body, err) { .... } 

然後,你的回調所認爲的response實際上是error值,因爲request.get()把誤差值在第一個參數,無論怎樣回調本身被聲明。

看到此問題的另一種方法是定義沒有定義參數的回調,然後使用arguments對象完全訪問它們。

function myCallback() { 
    console.log(arguments[0]); // err value 
    console.log(arguments[1]); // response value 
    console.log(arguments[2]); // body value 
} 

回調中的返回值也是如此。如果您使用的是Array.prototye.map(),則需要一個傳遞三個參數的回調函數並返回一個新的數組元素。即使您正在實施回調,您也必須定義與該合同兼容的回調。