【问题标题】:Does anyone know of a JS Chaining library that allows for deferred execution of methods? [closed]有谁知道允许延迟执行方法的 JS 链接库? [关闭]
【发布时间】:2013-06-01 16:43:52
【问题描述】:

我正在寻找一个库,它允许我轻松地将方法链接在一起,但推迟它们的执行,直到在链中进一步提供参数:

chain
    .scanDirectory  ( '/path/to/scan' )
        .recursively()
        .for        ( /\.js$/i        )
    .cache()
    .provideTo      ( '0.locals'      )
        .as         ( 'scripts'       )
    .defer();

重要的是 scanDirectory 函数背后的代码在定义为递归并查找 .js 文件之前不会被实际调用。

我不太确定如何从逻辑上进行设置,以便我可以执行以下操作:

chain
    .scanDirectory( '/path/to/scan' )
    .scanDirectory( '/another/path' )
        .for      ( /\.js$/i        ) // provided to both paths above?
    .doSomethingElse()

这就是为什么我正在寻找一个可能有更成熟的想法来实现这一点的库:)

【问题讨论】:

  • 试试那个。这是一个旧的,但它很好:) github.com/chriso/chain.js
  • @thinklinux:确实不错,但我不确定这是否正是他心目中的范式。有趣的库。 (我认为你应该保留这个作为答案)
  • @haylem:它基本上只是一个链接,所以我将它转换为评论。见meta.stackexchange.com/questions/8231/…
  • @ThiefMaster:对,好点,但也许先用评论通知 thinklinux 会更好,因为他可以即时扩展他的答案。当您切换评论时,我正在输入我的评论。许多人一边走一边勾勒出他们的答案,然后从简单的事情开始。我知道我这样做了,如果在键入我的后续内容的过程中我会意识到我的答案已被删除并且我现在需要创建一个新答案只是因为我没有得到10 分钟的编辑“宽限期”。
  • @thinklinux -- 链看起来很酷,但它非常线性。想把它打破一点:)

标签: javascript


【解决方案1】:

请注意,您一定会找到解决此问题的全能解决方案。

看起来您正在寻找一个通用的解决方案来解决需要已经融入库的东西。我的意思是,我确定有些库具有此功能,但它们不会自动挂接到其他库上(如果他们专门为您想要定位的库的正确版本实现了覆盖,也许)。

但是,在某些情况下,您可能希望查看 Stream.js 库,它可能涵盖了足够多的数据相关案例,让您感兴趣:

【讨论】:

  • 是的,我正在寻找具有更多功能的 Promise 库。 Stream 看起来很酷,但似乎与我想要完成的想法截然不同:)
【解决方案2】:

正如@Jordan Doyle 在他的comment 中所说:

只需返回this

因此,对象中的每个方法都应在 return 语句中返回对象,以便您可以链接到另一个方法。

例如:

var obj = new (function(){

   this.methOne = function(){
      //...
      return this;
   }

   this.methTwo = function(){
      //...
      return this;
   }

   this.methThree = function(){
      //...
      return this;
   }

})();

//So you can do:
obj.methOne().methTwo().methThree();

【讨论】:

  • 您的帖子已被删除,因为它被粘贴在两个地方。
  • @GeorgeStocker 另一个帖子已被 OP删除...我看不出当另一个帖子不再存在时如何删除该帖子?这是一些内部脚本吗?
  • 这并不能真正解决尝试以某种方式将参数放入方法的问题
  • @GeorgeStocker 这是一个奇怪的错误...但请下次删除检查以确保删除正确的内容:-) 谢谢,你'是友好的邻居尼尔 ^_^
  • 我从未说过这是一个错误。
【解决方案3】:

这篇文章讲的是JS中的执行类型,文末有相关库的链接

在 JavaScript 中执行

在 JS 中有两种执行方式:

  • 同步 - 在调用时立即发生的事情
  • 异步 - 当前代码运行完成后发生的事情,也就是您所说的延迟。

同步

您可以同步地将动作和参数推送到队列结构中,并使用.run 命令运行它们。

你可以这样做:

var chain = function(){
   var queue = []; // hold all the functions

   function a(param){
       //do stuff, knowing a is set, may also access other params functions set
   }
   return {
       a:function(someParam){
          queue.push({action:a,param:someParam});
          return this;
       },
       ... // more methods
       run:function(){
           queue.forEach(function(elem){ // on each item
               elem.action.apply(null,param);//call the function on that item
           });
       }
   };
}

当你调用run时,这将执行队列中的所有函数,语法类似于

chain().a(15).a(17).run();

异步

你可以简单地设置一个超时,你不需要为此使用像.run这样的东西。

var chainAsync = function(){ // 不需要队列

   function a(param){
       //do stuff, knowing a is set, may also access other params functions set
   }

   return {
       a:function(someParam){
          setTimeout(a,0,someParam);
          return this;
       },
       ... // more methods
   };
}

用法类似于

chain().a(16).a(17);

一些问题:

  • 如果你想在函数之间共享参数,你可以将它们存储在对象本身的某个地方(除了队列之外还有一个var state)。

  • 可以是同步的,也可以是异步的。您无法通过上下文检测其中一个。正在为 ES6 构建解决方法。

更多资源

【讨论】:

  • “它要么是同步的,要么是异步的。你无法通过上下文检测其中一个。正在为 ES6 构建解决方法。” -- Q 很好地解决了这个问题。如果一个函数返回一个未解决的承诺,其他一切都会透明地延迟。如果它返回一个已解决的承诺,或者任何不是承诺的东西,它是立即的。但这并不能解决我的语法问题 :) 感谢您的资源,现在查看它们以找到任何特别有价值的东西:)
  • Q 是一个非常好的库,它确实包含了问题的解决方案(尽管它们在大多数浏览器中还不能工作,如果你在源代码中检查Q.async,你可以使用yield这使得语法非常好。请参阅讨论该主题的this blog post
  • @cwolves Q 在浏览器上可以正常工作,不用担心 :) 生成器(即使用yield)仅在您打开正确标志的情况下在 Firefox 和 Chrome 中工作。生成器是一个很棒的东西,但实际上不在这个问题的范围内。这种协程语法的整体概念非常好,它确实像 C# 中的 async/await 一样奇迹,并且在未来几年将非常有趣。我同意即使不使用yield,Q 的解决方法也非常好。我还认为它是目前 JavaScript 中最成熟的 Promise 库,也是我唯一会在生产代码中使用的库。
  • 我也使用过async,但这是一个非常不同的流程。并且生成器规范很好,我还没有完全检查所有的 ES6。我想我只是短暂地看到了它们,但还没有完全深入。
  • @cwolves 很好,我的意思是 async/await 是 C# 构造,而不是 JS 库 async(这本身很有趣)。
【解决方案4】:

我不知道是否有构建此类方法的库,但您可以轻松地自己构建该功能。基本上,它将是一个带有 setter 方法和一个 execute 函数的设置对象(在您的情况下,defer)。

function Scanner() {
    this.dirs = [];
    this.recurse = false;
    this.search = "";
    this.cache = false;
    this.to = "";
    this.name = "";
}
Scanner.prototype = {
    scanDirectory: function(dir) {
        this.dirs.push(dir);
        return this,
    },
    recursively: function() {
        this.recurse = true;
        return this;
    },
    for: function(name) {
        this.search = name;
        return thsi;
    },
    cache: function() {
        this.cache = true;
        return this;
    },
    provideTo: function(service) {
        this.to = service;
        return this;
    },
    as: function(name) {
        this.name = name;
        return this;
    },
    defer: function() {
        // now, do something with all the given settings here
    },
    doSomethingElse: function() {
        // now, do something else with all the given settings here
    }
};

这是构建fluent interface 的标准方法。当然,您也可以创建一个辅助函数,向该函数传递一个方法名到设置映射,如果它太长,它会为您编写方法:-)

【讨论】:

  • 是的,我知道我可以构建一个,但我认为我需要内置的 Promise 等。但是你的模型不太好用,例如在我想methodA().as('foo').methodB().as('bar')的情况下。 methodB需要得到methodA的结果,as参数不同
  • 呃,没有最终调用……实际上我只看到了这种模式用于初始化实例,而不是为方法提供参数。我会想到一些方向:1)使as成为调用并让methodA/B仅设置一个关于应该触发什么的标志2)使它们成为不同类的实例(或至少是一个新实例),以便@987654331 @ 将是两个不同的函数 3) 将调用反转为 as('foo').methodA().as('bar').methodB(),然后我的模型就可以工作了。 Promise 集成对您来说应该不是什么大问题,要么将其放在数据属性上,要么将其用作 mixin。
  • 我希望方法先行,所以我可以这样做:var dir = chain.scan( '/path' ) ... dir.find( '.js' ).recursively().run() ... dir.find( '.css' ).run()。目前我在想我会有方法和提供者。每当命中链中的方法时,前一个方法将与所有提供程序一起运行。 run 将是一个什么都不做的方法 :) 并且肯定会着眼于让方法提供新的类实例,并在此之前提供链的副本
  • 是的,如果你到处都有run() 后缀(或者,隐含地,在新的方法调用中),那么让方法先出现是没有问题的。只有当你想避免它变得非常复杂时:-)
  • 好吧,我想避免它出现在链的中间(例如原始问题中的示例)。但我还需要在最后告诉它“嘿,现在做点什么”
【解决方案5】:

您需要一个队列来维护方法链的异步和同步性。

这是我为一个项目所做的使用 jQuery.queue 的实现:

function createChainable(options) {
    var queue = [];

    var chainable = {

        method1 : function () {
            queue.push(function(done){
                // code here
                done();
            });
            return chainable;
        },

        exec1 : function () {
            queue.push(function(done){
                // code here
                done();
            });
            $.queue(ELEMENT, QUEUE_NAME, queue).dequeue(QUEUE_NAME);
            return chainable;
        }
    };

    return chainable;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多