[英]Callback Confusion and Collecting Data in Node
我是Node的新手,在跟蹤這里發生的事情時遇到了麻煩。 我的評論在下面,但基本上我真的很難理解為什么utils.collectData中的回調在那里(第二個參數)以及它如何任意添加到messages數組中。 我怎么知道將來自然要這樣做? 我知道collectData函數定義為將回調作為其第二個參數,所以讓我們從那里開始...
var utils = require('./utils');
"POST": function(request, response) {
//collect the data
utils.collectData(request, function(message) {
message.objectID = ++objectIDcounter;
messages.push(message);
utils.sendResponse(response, {
objectID: message.objectID
}, 201)
})
}
// this is in utils.js:
//why is a callback parameter passed to this function?
exports.collectData = function(request, callback) {
var data = ""
request.on('data', function(chunk) {
data += chunk;
})
request.on('end', function() {
//why is the callback applied here?
//Also, we are parsing the data here. why? because it is a buffer or a string here?
callback(JSON.parse(data));
})
}
Node.js中的異步操作遵循簡單且一致的模式。 掌握這一點將使您的體驗更加愉悅,應用程序更快,更穩定。
我認為這里的其他答案有點漏了點。 您正在調用的方法遵循Node.js生態系統中無處不在的異步模式。 有多種模式可以簡化此操作,但是您的首要任務應該是徹底了解正在發生的事情以及對代碼有什么影響。 很簡單:
asyncFunction(functionArguments, callback);
當您調用任何異步函數時,腳本的執行將在該函數的結果掛起時繼續執行。 由於無法保證何時可以准備好結果,因此在繼續操作之前,請為功能提供預期的結果。 通常,您提供的回調將是一個匿名函數,例如:
getExternalData('http://example.com', function(err, data) {
console.log('I got the data!');
// presumably do something with the data
});
回調幾乎總是采用兩個參數: err
和data
(或err
和result
,或err
和whateverYouAreLookingFor
)。 如果函數中發生錯誤,則該錯誤將返回到您的回調中,並且如果該函數的執行產生了任何數據,則該錯誤也將返回到您的回調中。
這種模式的優點在於,您永遠不會被迫阻塞事件循環:無論任務的復雜性如何,腳本都將保持愉快的響應。 當老板在星期五的午餐后將構思不佳的項目放到辦公桌上,然后提早打工去打高爾夫球時,您實際上是在扮演異步功能。
這里的挑戰是,在調用回調時,它是原始請求的唯一存活鏈接。 其含義是雙重的:
任何用於處理響應的邏輯都必須包含在回調中或回調可以訪問; 和
對於處理異步函數拋出的任何錯誤,try / catch塊完全沒有用。
第一個含義是通常被稱為“回調地獄”的起源:在回調內的回調中深度嵌套的回調。 您可以通過預先計划,使函數較小並遵循相同的參數約定來輕松避免這種情況。
第二個含義意味着您的回調必須檢查錯誤。 通常,您不會看到拋出錯誤,因為在此模式下安全處理拋出錯誤的唯一方法是將幾乎所有代碼都放在try / catch塊中。 相反,錯誤將作為第一個參數傳遞給回調。 如果未生成錯誤,則第一個參數將為null。
const myCallback = function(err, data) {
if (!!err) {
console.log('Well, that was a failure');
return err;
}
console.log('Everything's great!');
}
最終,它有點冗長,但是讓您適應這種模式至關重要。 一些核心模塊具有正常和同步版本的功能,例如fs.readFile
和fs.readFileSync
。 不要屈服於使用它們; 一旦習慣了異步,它就非常簡單,而且剛開始時,您需要獲得所有可能的實踐。
祝你好運。
NodeJ的主要功能之一就是並發性(以一種簡單的方式)。 開始在NodeJ中進行編程的最好方法是認為所有與外部資源交互的代碼都必須遵循以下一種模式:
為什么是這樣?
當您以異步方式調用外部資源(HTTP服務,文件等)時。 主進程創建一個內部線程並執行代碼,這樣做是為了不阻塞主進程。
回調:
這是在javascript中管理並發的第一種方法,因為函數是一流的,所以您只傳遞要執行的函數,而主函數則在調用時進行選擇。
在您的示例中,您正在使用這種方法。 您正在從請求中讀取數據並存儲在本地變量中,當請求啟動事件“ end”時,您選擇使用數據作為參數調用回調,而“ POST”使用該數據來操縱消息並發送響應。
將來存在另外兩個選項,今天都可以使用,但是Async / Await處於tc39的第2階段http://tc39.github.io/ecmascript-asyncawait/ 。
諾言:
這是當今最流行的方式,您可以將本機與NodeJ的版本4一起使用,也可以使用Q或BlueBird之類的庫。 這項工作有點不同,我建議閱讀有關promise的郵寄文章 ,這里我將展示使用promise編寫的代碼:
var utils = require('./utils');
"POST": function(request, response) {
//collect the data
utils.collectData(request)
.then(function(message) {
message.objectID = ++objectIDcounter;
messages.push(message);
return utils.sendResponse(response, {
objectID: message.objectID
}, 201);
}))
.catch(function(err) {
//Some error happend with the reques
});
}
// this is in utils.js:
//why is a callback parameter passed to this function?
exports.collectData = function(request) {
return new Promise(function (resolve, reject) {
var data = ""
request.on('data', function(chunk) {
data += chunk;
});
request.on('end', function() {
resolve(JSON.parse(data));
});
request.on('error', function(err) {
reject(err);
});
}
}
甚至當我從Java開始使用NodeJS編程時,因為這是設計程序從阻塞IO到非阻塞IO的重大轉變,我也面對着上面的代碼的理解。
在非阻塞IO中,一切都基於事件和回調進行。 在上面的代碼中,調用collectData時,nodejs(eventloop)將等待on(帶有回調以收集數據)和on(帶有您提供的用於處理完成的請求的回調)事件。
在NodeJS中很簡單,任何阻塞代碼(網絡調用或對任何IO設備的訪問)都將標記一個事件,該事件將在I / O操作完成后觸發。 希望這可以幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.