JavaScript中的流控制

时间:2010-12-20 23:51:53

标签: javascript javascript-events

是否可以在JavaScript中编写此流控制?

MyLib.get = function() { /* do something */ next(); };
MyLib.save = function() { /* do something */ next(); };
MyLib.alert = function() { /* do something */ next(); };

MyLib.flow([
  MyLib.get(),
  MyLib.save(),
  MyLib.alert()
], function() {
  // all functions were executed
});

2 个答案:

答案 0 :(得分:0)

是的,但有两件事要知道:

  1. 您应该将 references 中的数组构建到您的函数中。这意味着你要离开(),因为你只想通过引用,而不是调用函数的结果!
  2. 您将不得不处理这样一个事实,即从对象的属性获取函数的引用将不会“记住”与该对象的关系。因此,“流”代码无法知道如何使用“MyLib”作为this上下文引用来调用函数。如果这很重要,那么您将需要创建在正确的上下文中运行“成员”函数的函数。
  3. 要在正确的上下文中运行函数,您可以拼凑一些类似Prototype框架(以及许多其他函数,Functional.js)提供的“bind”函数,或者来自jQuery的$.proxy()。这并不难,可能看起来像这样:

    function bindToObject(obj, func) {
      return function() {
        func.apply(obj, arguments);
      }
    }
    

    然后你会像这样使用它:

    MyLib.flow([
      bindToObject(MyLib, MyLib.get),
      bindToObject(MyLib, MyLib.save),
      bindToObject(MyLib, MyLib.alert)
    ]);
    

    如果需要传入参数,可以修改“bindToObject”:

    function bindToObject(obj, func) {
      var preSuppliedArgs = Array.prototype.slice.call(arguments, 2);
      return function() {
        func.apply(obj, preSuppliedArgs.splice(arguments));
      }
    }
    

    假设您希望在调用“bound”函数时将其他参数传递到参数列表的末尾。在你的情况下,我怀疑你是否想要这样做,所以你可以放弃那个“splice()”电话。

答案 1 :(得分:0)

这看起来像继续传递风格。但是,通常在该样式中,每个函数都使用next函数作为参数,如下所示:

MyLib.get = function(next) { /* do something */ next(); };
MyLib.save = function(next) { /* do something */ next(); };
MyLib.alert = function(next) { /* do something */ next(); };

正如Pointy指出的那样,你通常会自己传递这些函数,而不必调用它们:

MyLib.flow([
  MyLib.get,
  MyLib.save,
  MyLib.alert
], function() {
  // all functions were executed
});

通过这些更改,下面的代码可能会有效。

现在,对于不熟悉的人来说,通过查看代码确切地说继续传递方式是如何工作的并不明显。我不认为我能在一个答案中说清楚。但我会试试。

在这种风格中,即使是无所事事的功能也不会完全是空的,但是必须打电话给下一个:

MyLib.do_nothing = function(next) { /* don't do something */ next(); };

一个重要的构建块是能够采用这种风格编写的两个函数并将它们链接在一起:

// This function takes two CPS functions, f1 and f2, as arguments.
// It returns a single CPS function that calls f1, then f2, then next().
MyLib._compose2 = function (f1, f2) {
    return function(next) {
        return f1(function () { return f2(next); });
    };
};

我认为这是最难理解的。

一旦你拥有了它,就可以用它将任意数量的函数粘合在一起:

MyLib._composeAll = function (arr) {       // Easy!
    var result = do_nothing;               // Start with the "empty" function,
    for (var i = 0; i < arr.length; i++)   // and one by one,
        result = MyLib._compose2(result, arr[i]);  // add each element of arr.
    return result;
};

一旦你有了这个,flow就不难写了:

MyLib.flow = function(items, next) {
    var f = MyLib._composeAll(items);
    f(next);
};

修复该代码中的所有错误留作练习。 ;)