难以用Q.js调用函数“然后”没有括号

时间:2014-07-09 21:29:01

标签: jquery promise q

我已经在我的页面上组装了一个小工具,并且在大多数情况下它似乎起作用,但当我尝试将其插入Q.js时,我有一点奇怪的行为。

通常,据我所知,你可以用这种方式调用函数。

Q(manager.tasks.init)
   .then(manager.tasks.start)
   .then(manager.tasks.fulfill)
   .then(manager.tasks.finish);

但是我似乎无法做到这一点,而是我必须调用它们并像函数一样显式地调用它们。像这样。

Q(manager.tasks.init())
   .then(manager.tasks.start())
   .then(manager.tasks.fulfill())
   .then(manager.tasks.finish());

这里可以看到完整的代码;

jsBin

现在,我可以使用括号,但我不明白为什么它正在这样做。我想了解这里发生了什么,所以任何信息都会受到赞赏。

1 个答案:

答案 0 :(得分:3)

记录我们在上述评论和对我的回答的评论中所经历的一些内容......

上述任何一种解决方案都没有真正正确编码。第一个问题有问题,因为this在Q调用回调时不会设置属性。

当你这样做时:

Q(manager.tasks.init)
   .then(manager.tasks.start)
   .then(manager.tasks.fulfill)
   .then(manager.tasks.finish);

Q会调用这些方法,但this指针不会像你想要的那样设置为manager.tasks。所以,当你在方法中做这样的事情时:

$(this).trigger("init:begin");

然后this不会成为你想要的东西,它将抛出异常并停止执行。您可以通过以下方式解决这个问题:

Q(manager.tasks.init.bind(manager.tasks))
   .then(manager.tasks.start.bind(manager.tasks))
   .then(manager.tasks.fulfill.bind(manager.tasks))
   .then(manager.tasks.finish.bind(manager.tasks));

这将导致this设置为manager.tasks。或者,您可以删除这些方法中this的任何用法,以便它们成为静态方法(这是您选择做的)。


第二个没有按照它应该传递给.then()的函数引用。

当你这样做时:

Q(manager.tasks.init())
   .then(manager.tasks.start())
   .then(manager.tasks.fulfill())
   .then(manager.tasks.finish());

JS解释器立即调用您的函数(当您将()放在最后时会发生什么)并将这些函数的返回值传递给每个.then()行。那不是你想要的。 .then()想要传递一个函数引用,以便promise库可以在以后执行该函数。在您的情况下,您的函数返回的承诺不是您应该传递给.then()的承诺。

因为在这些方法中没有实际的异步操作,所以这似乎可以正常工作,因为它按顺序调用了操作,但只要你在其中任何一个实际上解决了承诺的异步操作,它就行不通了正确。


对于perform方法的问题,您需要使用在reduce操作中创建名为results的延迟/保证。我也改变它以在setTimeout()之前运行reduce,因为它对我来说似乎有点干净(更容易理解)。您正在设置要完成的所有工作,然后在setTimeout()中通过解决链中的第一个延迟来开始工作。

然后,它返回从list.reduce()操作返回的链式承诺,并使用链式.then()处理程序来知道何时输出"fulfill:end"消息。

manager.tasks.fulfill = function () {
    // alert the task manager that we're beginning this phase
    $(manager.tasks).trigger("fulfill:begin");

    // create a placeholder for the result of all of the items in the list
    var results = Q.defer();

    setTimeout(function(){
        // resolve the first defer we created to 
        //    let the `.then()` chain start to run
        results.resolve();
    }, 6000);

    // now add all then `.then()` onto the results
    // these functions won't run yet because the first defer has not yet resolved
    return list.reduce(function(i, f) {
        return i.then(f);
    }, results.promise).then(function() {
        // alert the task manager that we're ending this phase
        // after all the callback promises have finished
        $(manager.tasks).trigger("fulfill:end");
    });
};

我认为如果你的回调返回这样的承诺,.enqueue()问题将得到解决:

  manager.tasks.enqueue(function(deferred){
    return function(){
      setTimeout(function(){ 
        console.log('test');
        deferred.resolve();     
      }, 3000);
      return deferred.promise;
    };
  });

如果这是我,我可能会更改.enqueue()实现,以便它处理promise的返回(因为它是创建它的那个),但这里的快速解决方案就是确保你的回调在执行时返回承诺。

您可以在此处查看jsFiddle的推导http://jsfiddle.net/jfriend00/JxJVs/,并实施这些更改,生成您在JPEG中显示的确切输出。