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

时间:2016-02-03 20:22:27

标签: jquery promise indexeddb

我有可变数量的$.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()。我在上面的代码中做错了什么?

1 个答案:

答案 0 :(得分:2)

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

它的设计目的是克服jQuery.when()的良好理解和良好容忍的问题,它只接受离散的承诺作为参数,而不是承诺数组。

这不是一个大问题的原因是因为javascript的本地Function.prototype.apply允许使用参数数组来代替离散参数调用任何函数(并且thisArgjQuery.when.all()被指定)。

事实上,如果你仔细阅读了你发现自定义方法的答案,那么你会发现它正是它为你做的。

完全不使用$.when.apply(null, putQueryArray).then(function(res) { ... }, function(err) { ... }); ,你会写:

$.when.apply($, putQueryArray)

许多人选择撰写thisArg,但第一个参数$.when未被null使用,而$.when.all()就足够了。

理解了所有这些并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()

如果您仍有问题,那么jQuery.Deferred()可能不会按照您的想法行事,或者只是一个错误的期望问题。

  

我希望它们在调用$ .when.all()时完成,并在其对应的.then()函数中执行代码,但我通过断点发现它立即执行.put()调用它,......

传递给objectStore.put(fav);的函数是同步执行的,因此list_of_keys = [] for obj in File.objects.all().values_list('metadata', flat=True) list_of_keys = list_of_keys + obj.keys() 确实会立即执行。目前尚不清楚您可能想要的替代行为。