jQuery.Deferred(function() {...}) 在调用 $.when(...) 之前执行

jQuery.Deferred(function() {...}) executing before I call $.when(...)

我有数量可变的 $.Deferred() 个对象,它们被推入数组以通过 $.when() 执行。根据 elsewhere on Stack Overflow 的建议,我决定采用手工编码的 $.when.all([$.Deferred(), ...]) 方法。

具体来说,$.Deferred() 对象包含一个函数,每个对象执行一个 indexedDB .put()。我希望它们在调用 $.when.all() 时完成,并在其对应的 .then() 函数中执行代码,但我通过断点发现它在调用它时立即执行 .put(),并执行javascript 一起绕过 .then() 函数并继续。

var putQueryArray = [];

_.each(favorites, function(fav) { // favorites being an array of updated indexedDB .get()s
  var objectStore = db.transaction(['store'], 'readwrite') // var db defined elsewhere
                        .objectStore('store');

  putQueryArray.push($.Deferred(function() {
    var update = objectStore.put(fav);  // This executes immediately, as verified in Chrome's Resources tab

    update.onsuccess = _.bind(function(e) {
      this.resolve(e);  // Even if I put a breakpoint here, it never triggers
    }, this);

    update.onerror = _.bind(function(e) {
      this.reject(e);
    }, this);
  }).promise());
});

// It appears this is ignored all together
$.when.all(putQueryArray).then(function(res) {  // I (think I) expect this line to execute the above array of $.Deferred()'s?
  //This function never executes
}, function(err) { ... });

我已经尝试了所有方法,从不将整个函数包装在 $.Deferred(function() { ... }); 中,而是将 $.Deferred 作为函数中的变量调用并返回它的承诺,到一起排除 .promise() 部分,两者都会导致它实际执行 .then() 函数,但不会实际执行 .put()。我在上面的代码中做错了什么?

answer where you discovered jQuery.when.all() 在使用之前定义了该方法。换句话说,jQuery.when.all() 是自定义的,而不是本机的 jQuery 方法。

它旨在克服 jQuery.when() 易于理解和容忍的问题,即它只接受离散的承诺作为参数,而不是一系列承诺。

这不是一个大问题的原因是因为 javascript 的原生 Function.prototype.apply 允许使用参数数组来调用任何函数而不是离散参数(对于 thisArg待定)。

事实上,如果您通读发现自定义方法的答案,那么您会发现这正是它为您所做的。

完整的,不使用 jQuery.when.all(),你会写:

$.when.apply(null, putQueryArray).then(function(res) {
    ...
}, function(err) {
    ...
});

许多人选择写 $.when.apply($, putQueryArray),尽管第一个参数 thisArg 没有被 $.when 使用,null 就足够了。


了解所有内容并 $.when.all() 安全安装(很可能是这种情况),然后您可以开始查看其他代码。

罪魁祸首似乎是延迟的方式 resolved/rejected。

尝试:

putQueryArray.push($.Deferred(function(dfrd) { // `dfrd` is a reference to the Deferred that will be returned 
    var update = objectStore.put(fav);
    // `dfrd.resolve` and `dfrd.reject` both have `dfrd` already bound in, so .bind() is not required.
    update.onsuccess = dfrd.resolve;
    update.onerror = dfrd.reject;
}).promise());

如果你还有问题,那么可能objectStore.put()并没有按照你想的那样工作,或者只是错误期望的问题。

I would expect them to complete upon calling $.when.all(), and execute code within it's corresponding .then() function, yet I discovered via breakpoints that it immediately executes the .put() upon invoking it, ...

传递给jQuery.Deferred()的函数是同步执行的,所以objectStore.put(fav);确实会立即执行。目前尚不清楚您可能想要什么替代行为。