延迟jquery的计时问题

时间:2013-04-05 18:20:57

标签: javascript jquery race-condition jquery-deferred deferred

这个问题是not asynchronous function executed as jQuery Deferred的精心提炼版本。

我们有2个jsfiddles:

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

  2. http://jsfiddle.net/UXSbw/1/ - 此处按预期触发进度事件。

  3. 唯一的区别是一行代码:

    setTimeout(dfd.resolve,1);
    

    dfd.resolve();
    

    问题是:

    1.   

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

    2. 我是否可以摆脱setTimeout()并且仍然会触发进度回调?

1 个答案:

答案 0 :(得分:1)

制作了一个大型重构,这里one final working example,进行了进度监控。

现在重要的部分。

  • 在调用resolve(with one exception)后,JQuery deferreds不会执行任何进度回调。在您的示例中(没有setTimeout),延迟会立即解决,无法运行进度。
  • 执行所有回调的钩子,尤其是进度回调,之前我们在最终的Deferred上触发enything。这是通过将最终的Deferred(现在的信标)传递给执行函数之后我们填充它的触发器来实现的。
  • 我重构了API,因此要执行的func是延迟不可知的。
  • 此解决方案在memo.then函数内使用closure局部(对于reduce迭代器函数)延迟,以继续执行链。
编辑:我忘记了你的第一个问题。 这种行为是通过closure(“x”函数中的dfd变量)来实现的。

函数“x”立即返回(在触发现在可以处理的通知事件之后,因为已经创建了执行链的所有Deferreds,并且已经挂起了“executePromiseQueueSync”的done,fail,progress hooks )。

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

JS VM产生后(它没有其他事情可做),setTimeout触发它的相关功能,(通过关闭)可以访问“已关闭”的dfd变量。延期已解决,链条可以继续。

EDIT2:Here is a refactored version增加了对长时间执行,延迟支持的功能的支持,它们会通知呼叫者他们的进度。

EDIT3:这是another version,没有下划线绑定和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)