【问题标题】:Flow control in JavaScriptJavaScript 中的流控制
【发布时间】:2010-12-20 23:51:53
【问题描述】:

这个流控制可以用 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
});

【问题讨论】:

  • 您打算将函数getsavealert 等传递给flow,还是传递调用这些函数的结果
  • 请添加更多详细信息以解释“所有功能都已执行”的含义。例如,让函数在控制台 (console.put) 上打印一些内容并写下您的预期输出。
  • @Anon 我正在尝试传递函数“获取、保存、警报”。
  • 然后省略括号。您当前正在执行它们。

标签: javascript javascript-events


【解决方案1】:

是的,但要知道两件事:

  1. 您应该将数组从references 构建到您的函数中。这意味着你离开了(),因为你只想传递引用,而不是调用函数的结果!
  2. 您将不得不处理这样一个事实,即从对象的属性中获取对函数的引用不会“记住”与该对象的关系。因此,“流”代码将无法知道如何使用“MyLib”作为this 上下文引用来调用函数。如果这很重要,您将需要创建在正确上下文中运行“成员”函数的函数。

要在正确的上下文中运行这些函数,您可以拼凑一些东西,例如由 Prototype 框架提供的“绑定”函数(以及其他许多函数,Functional.js),或来自 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));
  }
}

假设您希望在调用“绑定”函数时传递额外的参数,以将其附加到参数列表的末尾。就您而言,我怀疑您是否愿意这样做,因此您可以省略“splice()”调用。

【讨论】:

  • 那么你想修改那个小小的“绑定”功能 - 我会更新我的答案。
【解决方案2】:

这看起来像延续传递风格。但是,通常在这种风格中,每个函数都将 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
});

通过这些更改,下面的代码可能会起作用。

现在,对于没有经验的人来说,仅仅通过查看代码就知道继续传递样式是如何工作的。我不认为我可以在一个答案中说清楚。不过我会试试的。

在这种风格中,即使是无所事事的函数也不会完全为空,而是必须调用 next:

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);
};

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-18
    • 1970-01-01
    • 2020-11-19
    • 2015-11-11
    • 1970-01-01
    相关资源
    最近更新 更多