在jQuery承诺的数组中添加ajax会导致意想不到的行为

Adding ajax in array for jQuery promise results in unexpected behaviour

本文关键字:意想不到 添加 承诺 jQuery 数组 ajax      更新时间:2023-09-26

我有一个each语句,使单独的AJAX请求,并将它们添加到一个数组,如:

var promises = [];
$items.each(function(k, v) {
   promises.push(
      $.ajax({
         url: ...,
         .... 
      }) 
   );
});

$.when.apply($, promises).done(function() { ... });

似乎,我不知道原因,第一次加载页面时,或当它被部署(我使用ASP。. NET MVC),当到达这个断点时,ajax已经对第一项执行了:

promises.push($.ajax ...

如果我刷新页面,那么一切工作正常,$.when正确执行ajax请求。但是,如果我部署应用程序,那么问题仍然存在。

为什么,第一次,是ajax请求已经调用(不是在$,.when)?我错在哪里?我没有JavaScript错误

如果代码不比示例复杂,您可以这样做

var get_promises = function() {
    var promises = [];
    return function () {
        if (promises.length === 0) {
            $items.each(function(k, v) {
               promises.push(
                  $.ajax({
                     url: ...,
                     .... 
                  }) 
               );
            });
        }
        return promises;
    }
}());
$.when.apply($, get_promises()).done(function() { ... });

我真不敢相信我建议了以下内容!!但我要拥有它:D

一种方法是使用所谓的"惰性"承诺

一个Promise/a + polyfill -主要用于Internet Explorer(包括11 - Edge,或者不管它在Windows 10中叫什么,都有原生Promise)

<script src="https://www.promisejs.org/polyfills/promise-6.1.0.js"></script>

一个延迟承诺实现,基于- https://github.com/then/lazy-promise -但修改为使用浏览器原生承诺 -注意,仅在firefox中测试,YMMV

var inherits = (function() {
    if (typeof Object.create === 'function') {
        return function inherits(ctor, superCtor) {
            ctor.super_ = superCtor
            ctor.prototype = Object.create(superCtor.prototype, {
                constructor: {
                    value: ctor,
                    enumerable: false,
                    writable: true,
                    configurable: true
                }
            });
        };
    } else {
        return function inherits(ctor, superCtor) {
            ctor.super_ = superCtor;
            var TempCtor = function () {};
            TempCtor.prototype = superCtor.prototype;
            ctor.prototype = new TempCtor();
            ctor.prototype.constructor = ctor;
        };
    }
}());
inherits(LazyPromise, Promise);
function LazyPromise(fn) { 
    var promise;
    if (!(this instanceof LazyPromise)) {
        return new LazyPromise(fn);
    }
    if (typeof fn != 'function') {
        throw new TypeError('fn is not a function');
    }
    this.then = function(onResolved, onRejected) {
        return (promise = promise || new Promise(function(resolve, reject) {
            setTimeout(function() {
                try { fn(resolve, reject) }
                catch (e) { reject(e) }
            }, 0);
        })).then(onResolved, onRejected);
    };
}

现在来改变你的代码-非常小

var promises = [];
$items.each(function(k, v) {
   promises.push(
      new LazyPromise(function(resolve, reject) { // wrap the (broken) jQuery "promise" in a Lazy Promise
          $.ajax({
             url: ...,
             .... 
          })
          .then(resolve, reject); // I assume $.ajax is "thenable", so resolve the wrapping Lazy promise;
      }) // end of Lazy Promise wrapper
   );
});
$.when.apply($, promises).done(function() { ... });

这可能有点矫枉过正,但它应该完全符合你在问题中所要求的