javascript - 如何在解决多个功能后才运行一个功能?

标签 javascript node.js events callback

我有几个功能,基本上可以为我的应用程序做准备。 这些准备功能完成后,我想运行我的应用程序的主循环。

因此,虽然准备函数彼此异步,但主循环仅在所有准备函数都已解析后才运行。

function prep1(x) { do something };
function prep2(x) { do something };
function prep3(x) { do something };

function mainLoop(x) { only start this function when all 3 prep ones are resolved };

我基本上是在学习 nodejs 中的控制流。我的问题是如何使用以下方法实现我的要求:

  1. 回调
  2. 事件
  3. promise (如果正在使用库,名称就足够了)

最佳答案

在 Node.JS 中有一些不同的控制流的方法。执行此操作的“传统”最先进方法是使用回调,但这会导致我们称之为“回调 hell ”或回旋镖效应的情况。您还可以使用promises库来处理回调 hell 。在 Node.JS 中进行控制流(除其他外)的另一种方法是使用流。

有关不同控制流技术的示例,请参见下文。

使用回调的示例:

function prep1(x, cb) { do something; cb(); };
function prep2(x, cb) { do something; cb(); };
function prep3(x, cb) { do something; cb(); };

function mainLoop(x) { };

prep1(x, function () {
    prep2(y, function () {
        prep3(z, function () {
            mainLoop();
        });
    });
});

// could be shortened to
prep1(x, prep2(y, prep3(z, mainLoop)));

如您所见,这可能会导致一些非常难看的代码。另外请注意,此代码不是并行运行的,而是串行运行的。如果您想在每个准备函数中进行某种异步操作的情况下并行运行它,请参阅下文了解它是如何工作的。

使用并行回调的示例:

// cb() is called inside some async operation
function prep1(x, cb) { do async; cb(y); };
function prep2(x, cb) { do async; cb(y); };
function prep3(x, cb) { do async; cb(y); };

function mainLoop(x) {
    // x is an array of values given by the callback in prep1-3
};

var numCalls = 0, result = [];
function maybeCallMainLoop(data) {
   if (++numCalls !== 3) {
       // Accumulate all responses given by  argument y from prep1-3
       result.push(data);
       return;
   }
   // run main loop when all functions are called
   mainLoop(result);
}

prep1(x, maybeCallMainLoop);
prep2(y, maybeCallMainLoop);
prep3(z, maybeCallMainLoop);

这并不是最干净、最健壮的方法。下一个例子是更好的方法。


解决这个问题的一种非常非常干净的方法是使用 async library .更具体地说 #parallel method

使用 #parallel method 的示例的 async library

// Signature of the callback: callback(error, value)
function prep1(x, cb) { do something; cb(null, "value"); };
function prep2(x, cb) { do something; cb(null, "value"); };
function prep3(x, cb) { do something; cb(null, "value"); };

function mainLoop(error, x) { };

async.parallel([
    prep1,
    prep2,
    prep3
], mainLoop);

the async readme 中查看更多信息


如您所说,第三种方法是使用 promise 。您将从每个准备函数返回一个 promise ,而不是等待执行 mainLoop

您可以使用 Q library这是一个符合 A* 的 promise 库。

Q library 中使用 promise 的示例

var Q = require('q');

// Signature of the callback: callback(error, value)
function prep1(x) { 
    // do something; 
    var deferred = Q.defer();
    deferred.resolve() // resolve promise
    return deferred.promise;
};
function prep2(x) { // same as prep1 };
function prep3(x) { // same as prep1 };

function mainLoop(result) { };

// Q.all returns a promise that is 
// resolved when all promises given are resolved
Q.all([
    prep1(x),
    prep2(y),
    prep3(z)
]).then(mainLoop);

参见 documentation of Q.all


这是解决它的一些方法。我并没有真正看到使用事件以漂亮的方式解决这个问题的方法——但它看起来很像带有并行回调的示例。带有一个标志,指示已完成的准备功能的数量。

您可以看到,使用 async 或 promises 之类的东西很容易理解和阅读。如果您只想获得“瘦”的结果(低 cyclomatic complexity 的功能),我可能会建议使用 async .如果您的准备工作如何以不同的方式使用一些复杂性和/或结果,那么 promise 将是最好的方法。

关于流的小尾注

在 Node.JS 中你还有一个叫做 streams 的东西.以最基本的方式,流是具有背压(一种停止数据流的方式)功能的可管理事件发射器。阅读 Daddy, what's a stream? 中的一个简单类比.

使用流,您可以拥有一个源并将其通过不同的转换流进行管道传输,并以某种汇点或端点结束流。这是一个系列而不是并行,但你可以用流做更多的事情。流与 promise 有一些共性。

使用流的示例

function prep1(x) { return stream; };
function prep2(x) { return stream; };
function prep3(x) { return stream; };

function mainLoop(result) { };

// Some start. E.g fs.createReadStream("somefile")
someStartStream
   .pipe(prep1(x))
   .pipe(prep2(y))
   .pipe(prep3(z))
   .on('end', mainLoop);

同样,这是一个顺序,而不是并行。这只是为了说明在 Node.JS 的控制流中您也可以使用流。

祝你好运!

关于javascript - 如何在解决多个功能后才运行一个功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24251135/

相关文章:

javascript - keyup 和 keydown 事件,如果用户打字太快

javascript - Reactjs - 无法从数组中获取值,未定义

node.js - Node 的模块函数返回值空/未定义?

node.js - Mongoose 中的 "__v"字段是什么

java - JComboBox 事件 - Swing

wpf - 是否可以伪造WPF鼠标悬停?

javascript - 使用 jQuery 延迟轮询

javascript - 尝试让 .modal ('show' )从右侧而不是顶部滑动元素

javascript - Mongodb 获取文档在集合中的位置

Mysql 重复事件