【问题标题】:timing issues with jquery deferredjquery延迟的时间问题
【发布时间】:2013-04-05 18:20:57
【问题描述】:

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

我们有 2 个 jsfiddles:

  1. http://jsfiddle.net/XSDVX/1/ - 尽管调用了 notify() 函数,但这里没有触发进度事件。

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

唯一的区别是一行代码:

setTimeout(dfd.resolve,1);

dfd.resolve();

问题是:

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

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

【问题讨论】:

  • 只是从上一个问题中添加一些背景信息,需要 setTimeout 的原因是已解决延迟对象不能有更多的进度事件绑定到它们。通过延迟解析,.then 能够绑定到进度事件。
  • 如果您意识到所有微妙的后果,这是非常错误的行为。
  • 其中有一部分我不太明白。当我们延迟解析时,.then 如何捕获在此回调返回之前调用的 .notify?想想看。 .then 获取从它的第一个参数返回的延迟对象,并从中创建一个新的延迟对象,绑定到它的完成进度和失败事件。如果在延迟返回之前调用了通知,那么即使使用 setTimeout,.then 如何捕获它?
  • 我可以看到.progress 的行为就像.done.fail,如果延迟已经表明一些进展,则立即调用回调。但这里似乎确实存在一个错误:文档明确指出,添加到已解决的 Deferred 的进度回调仍会立即被调用,但 .then 似乎违反了合同的这一部分。
  • 像@KevinB 一样,我更惊讶的是 .notifies 在延迟解决时通过链接的 .thens 传递,而不是在立即解决时不通过 .notifies。

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


【解决方案1】:

做了一个很大的重构,这里是one final working example,,带有进度监控。

现在是重要的部分。

  • JQuery 延迟不执行任何进度回调,在解析被调用后 (with one exception)。在您的示例中(没有 setTimeout),延迟立即解决,没有机会运行进度。
  • 执行所有回调的挂钩,尤其是进度回调,我们在最终的 Deferred 上触发 enything。这是通过将最终的 Deferred(现在的信标)传递给执行函数来实现的,我们已经填充了它的触发器。
  • 我重构了 API,因此要执行的 func 与延迟无关。
  • 此解决方案在 memo.then 函数中使用本地(到 reduce 迭代器函数)Deferred 的 closure,以继续执行链。

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

函数“x”立即返回(在触发一个现在可以处理的通知事件后,因为执行链的所有延迟都已创建,并且“executePromiseQueueSync”的done,fail,progress hooks已被hook )。

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

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

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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-12
    • 2020-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-10
    相关资源
    最近更新 更多