我有两个异步运行的函数。我想使用瀑布模型来编写它们。问题是,我不知道怎么..。
下面是我的代码:
var fs = require('fs');
function updateJson(ticker, value) {
//var stocksJson = JSON.parse(fs.readFileSync("stocktest.json"));
fs.readFile('stocktest.json', function(error, file) {
var stocksJson = JSON.parse(file);
if (stocksJson[ticker]!=null) {
console.log(ticker+" price : " + stocksJson[ticker].price);
console.log("changing the value...")
stocksJson[ticker].price = value;
console.log("Price after the change has been made -- " + stocksJson[ticker].price);
console.log("printing the the Json.stringify")
console.log(JSON.stringify(stocksJson, null, 4));
fs.writeFile('stocktest.json', JSON.stringify(stocksJson, null, 4), function(err) {
if(!err) {
console.log("File successfully written");
}
if (err) {
console.error(err);
}
}); //end of writeFile
} else {
console.log(ticker + " doesn't exist on the json");
}
});
} // end of updateJson
你知道我如何使用瀑布来编写它,这样我就可以控制它了吗?请给我写一些例子,因为我是node.js的新手
发布于 2014-09-07 06:24:38
首先确定步骤并将其编写为异步函数(接受回调参数)
function readFile(readFileCallback) { fs.readFile('stocktest.json',function (error,file) ){ if (error) { readFileCallback(error);} else { readFileCallback(null,file);} });}
function processFile(file,processFileCallback) { var stocksJson = JSON.parse(file);if (stocksJsonticker != null) { stocksJsonticker.price = value;fs.writeFile('stocktest.json',JSON.stringify(stocksJson,null,4),function (error) { if (err) { processFileCallback(error);} else {console.log(“文件写入成功”);processFileCallback(null);} });} else { console.log(ticker +“json上不存在”);processFileCallback(null);//回调始终调用一次(且只调用一次)} }
请注意,我在这里没有具体的错误处理,我将利用async.waterfall将错误处理集中在同一位置。
另外要注意,如果您有( if /else/switch/...)在异步函数的分支中,它总是调用回调一次(并且只调用一次)。
使用async.waterfall即插即用
async.waterfall([
readFile,
processFile
], function (error) {
if (error) {
//handle readFile error or processFile error here
}
});
干净的例子
前面的代码过于冗长,以使解释更清晰。下面是一个完整的干净示例:
async.waterfall([
function readFile(readFileCallback) {
fs.readFile('stocktest.json', readFileCallback);
},
function processFile(file, processFileCallback) {
var stocksJson = JSON.parse(file);
if (stocksJson[ticker] != null) {
stocksJson[ticker].price = value;
fs.writeFile('stocktest.json', JSON.stringify(stocksJson, null, 4), function (error) {
if (!err) {
console.log("File successfully written");
}
processFileCallback(err);
});
}
else {
console.log(ticker + " doesn't exist on the json");
processFileCallback(null);
}
}
], function (error) {
if (error) {
//handle readFile error or processFile error here
}
});
我留下了函数名,因为它有助于提高可读性,并有助于使用chrome调试器等工具进行调试。
如果使用underscore (on npm),还可以将第一个函数替换为_.partial(fs.readFile, 'stocktest.json')
发布于 2014-09-07 06:27:12
首先也是最重要的,确保你的read the documentation regarding async.waterfall
。
现在,关于瀑布控制流有几个关键部分:
_
_
_
err
),则它将短路并立即从先前执行的函数中调用“applied”/“finish”/“done”完成,按顺序依次调用控制流中的下一个函数。_
err
_applied__
err
参数,而不是“中间”回调(即cbAsync
回调):第一个参数将是错误(如果有错误),第二个参数(第三个、第四个...等)参数将是要传递给后续操作的任何数据。第一个目标是在引入async.waterfall
的同时,让您的代码几乎逐字地工作。我决定删除您的所有console.log
语句并简化您的错误处理。这是第一次迭代(未测试的代码):
var fs = require('fs'),
async = require('async');
function updateJson(ticker,value) {
async.waterfall([ // the series operation list of `async.waterfall`
// waterfall operation 1, invoke cbAsync when done
function getTicker(cbAsync) {
fs.readFile('stocktest.json',function(err,file) {
if ( err ) {
// if there was an error, let async know and bail
cbAsync(err);
return; // bail
}
var stocksJson = JSON.parse(file);
if ( stocksJson[ticker] === null ) {
// if we don't have the ticker, let "complete" know and bail
cbAsync(new Error('Missing ticker property in JSON.'));
return; // bail
}
stocksJson[ticker] = value;
// err = null (no error), jsonString = JSON.stringify(...)
cbAsync(null,JSON.stringify(stocksJson,null,4));
});
},
function writeTicker(jsonString,cbAsync) {
fs.writeFile('stocktest.json',jsonString,function(err) {
cbAsync(err); // err will be null if the operation was successful
});
}
],function asyncComplete(err) { // the "complete" callback of `async.waterfall`
if ( err ) { // there was an error with either `getTicker` or `writeTicker`
console.warn('Error updating stock ticker JSON.',err);
} else {
console.info('Successfully completed operation.');
}
});
}
第二次迭代进一步划分了操作流程。它将其放入更小的面向单一操作的代码块中。我不打算评论它,它不言而喻(同样,未经测试):
var fs = require('fs'),
async = require('async');
function updateJson(ticker,value,callback) { // introduced a main callback
var stockTestFile = 'stocktest.json';
async.waterfall([
function getTicker(cbAsync) {
fs.readFile(stockTestFile,function(err,file) {
cbAsync(err,file);
});
},
function parseAndPrepareStockTicker(file,cbAsync) {
var stocksJson = JSON.parse(file);
if ( stocksJson[ticker] === null ) {
cbAsync(new Error('Missing ticker property in JSON.'));
return;
}
stocksJson[ticker] = value;
cbAsync(null,JSON.stringify(stocksJson,null,4));
},
function writeTicker(jsonString,cbAsync) {
fs.writeFile('stocktest.json',jsonString,,function(err) {
cbAsync(err);
});
}
],function asyncComplete(err) {
if ( err ) {
console.warn('Error updating stock ticker JSON.',err);
}
callback(err);
});
}
最后一次迭代使用了一些bind
技巧来减少调用堆栈并增加可读性(IMO),这也是未经测试的:
var fs = require('fs'),
async = require('async');
function updateJson(ticker,value,callback) {
var stockTestFile = 'stocktest.json';
async.waterfall([
fs.readFile.bind(fs,stockTestFile),
function parseStockTicker(file,cbAsync) {
var stocksJson = JSON.parse(file);
if ( stocksJson[ticker] === null ) {
cbAsync(new Error('Missing ticker property in JSON.'));
return;
}
cbAsync(null,stocksJson);
},
function prepareStockTicker(stocksJson,cbAsync) {
stocksJson[ticker] = value;
cbAsync(null,JSON.stringify(stocksJson,null,4));
},
fs.writeFile.bind(fs,stockTestFile)
],function asyncComplete(err) {
if ( err ) {
console.warn('Error updating stock ticker JSON.',err);
}
callback(err);
});
}
发布于 2014-09-07 06:41:22
基本上,nodejs (以及更一般的javascript)需要一些时间来执行(无论是I/O还是cpu处理)的函数通常是异步的,因此事件循环(为了简单起见,它是一个不断检查要执行的任务的循环)可以调用第一个函数下面的函数,而不会阻塞响应。如果您熟悉其他语言,如C或Java,您可以认为异步函数是在另一个线程上运行的函数(在javascript中不一定是真的,但程序员不应该关心它),当执行终止时,这个线程通知主线程(事件循环线程)作业已经完成,并且有结果。
如上所述,一旦第一个函数结束了它的作业,它就必须能够通知它的作业已经完成,并且它会调用您传递给它的回调函数。举个例子:
var callback = function(data,err)
{
if(!err)
{
do something with the received data
}
else
something went wrong
}
asyncFunction1(someparams, callback);
asyncFunction2(someotherparams);
执行流程将调用: asyncFunction1、asyncFunction2和下面的每个函数,直到asyncFunction1结束,然后调用作为最后一个参数传递给asyncFunction1的回调函数,以便在没有发生错误的情况下对数据执行某些操作。
因此,要使2个或更多异步函数仅在它们结束时才能依次执行,您必须在它们的回调函数中调用它们:
function asyncTask1(data, function(result1, err)
{
if(!err)
asyncTask2(data, function(result2, err2)
{
if(!err2)
//call maybe a third async function
else
console.log(err2);
});
else
console.log(err);
});
result1是asyncTask1的返回值,result2是asyncTask2的返回值。你可以用这种方式嵌套你想要的多少异步函数。
在本例中,如果您希望在updateJson()之后调用另一个函数,则必须在此行之后调用它:
console.log("File successfully written");
https://stackoverflow.com/questions/25705067
复制相似问题