延迟jquery的计时问题

mno*_*tka 6 javascript jquery race-condition deferred jquery-deferred

这个问题是精心提炼的非异步函数版本,作为jQuery Deferred执行.

我们有2个jsfiddles:

  1. http://jsfiddle.net/XSDVX/1/ - 尽管调用了notify()函数,但不会触发progress事件.

  2. http://jsfiddle.net/UXSbw/1/ - 这里按预期触发进度事件.

唯一的区别是一行代码:

setTimeout(dfd.resolve,1);
Run Code Online (Sandbox Code Playgroud)

dfd.resolve();
Run Code Online (Sandbox Code Playgroud)

问题是:

  1. 当我们延迟解决时,如何捕获在此回调返回之前调用的.notify?想一想..then获取从它的第一个参数返回的延迟对象,并从中创建一个新的延迟对象,绑定到它完成的进度和失败事件.如果在返回deferred之前调用了notify,那么即使使用setTimeout,如何捕获它呢?(感谢/sf/users/28045811/询问此问题)

  2. 我可以摆脱setTimeout()并仍然有进展回调被解雇?

bas*_*sos 1

进行了一次重大重构,这是一个最终的工作示例,带有进度监控。

现在是重要的部分。

  • 在调用解析之后,JQuery 延迟不会执行任何进度回调(有一个例外)。在您的示例中(没有 setTimeout),延迟会立即解决,没有机会运行进度。
  • 在我们触发最终 Deferred 上的任何内容之前,执行所有回调的挂钩,尤其是进度回调。这是通过在填充触发器后将最终的 Deferred(现在是信标)传递给执行函数来实现的。
  • 我重构了 API,因此要执行的函数是延迟不可知的。
  • 该解决方案在 memo.then 函数内部使用本地(到reduce 迭代器函数)Deferred闭包,以便继续执行链。

编辑:我忘记了你的第一个问题。此行为是通过闭包(“x”函数中的 dfd 变量)的方式实现的。

函数“x”立即返回(在触发现在可以处理的通知事件之后,因为执行链的所有延迟都已创建,并且“executePromiseQueueSync”的完成、失败、进度挂钩已被挂钩)。

此外,setTimeout 的函数会在闭包中“关闭”dfd,因此尽管“x”已返回,但它仍可以访问该变量。“then”调用继续创建链接到第一个延迟的下一个延迟。

JS VM 屈服后(它没有其他事情要做),setTimeout 触发它的关联函数,该函数(通过闭包)可以访问“已关闭”的 dfd 变量。延迟已解决,链可以继续。

EDIT2:这是一个重构版本,添加了对长时间执行、延迟支持的函数的支持,它们通知调用者其进度。

EDIT3:这是另一个版本,没有下划线绑定,并带有 jq-ui 进度条示例。

顺便说一句,这对于复杂的应用程序初始化例程来说是一个非常好的主意。

来源(第一版)

function executePromiseQueueSync(queue, beacon){
    var seed = $.Deferred(),
        le = queue.length,
        last;
    beacon.notify(0);
    last = _.reduce(queue, function(memo, ent, ind){
       var df = $.Deferred();
        df.then(function(){
            console.log("DBG proggie");
            beacon.notify((ind+1)/le*100);
        });
        console.log("DBG hook funk "+ind);
        memo.then(function(){
          console.log("DBG exec func "+ind);
          ent.funct.apply(null, ent.argmnt);
          df.resolve();
        });

        return df.promise();
    }, seed.promise());
    last.then(function(){
        beacon.resolve(100)
    });
    seed.resolve(); // trigger

    return beacon.promise();
}

function x(){
    // do stuff
    console.log("blah");
}

var promisesQueue = [],
     beacon = $.Deferred(); 

promisesQueue.push({funct: x, argmnt:[]});
promisesQueue.push({funct: x, argmnt:[]});
promisesQueue.push({funct: x, argmnt:[]});

function monTheProg(pct) 
{
    console.log('progress '+pct);
}

// first hook, then exec
beacon.then(function(){
        console.log('success');
    }, function(){
        console.log('failure');
    }, monTheProg);

// do the dance
executePromiseQueueSync(promisesQueue, beacon)
Run Code Online (Sandbox Code Playgroud)