简体   繁体   English

在数组中为jQuery Promise添加Ajax会导致意外行为

[英]Adding ajax in array for jQuery promise results in unexpected behaviour

I have an each statement which make separate AJAX requests and adds them to an array like: 我有一个each语句,它们分别发出AJAX请求,并将它们添加到数组中,例如:

var promises = [];

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


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

It seems that, I don't know the reason, for the first time when loading the page, or when it is deployed (I use ASP.NET MVC), the ajax is already executed for the first item when it reaches this breakpoint: 似乎,我不知道原因,这是第一次加载页面或部署页面时(我使用ASP.NET MVC),当第一个项目到达此断点时,ajax已经被执行:

promises.push($.ajax ...

If I refresh the page, then everything works fine, and $.when correctly executes the ajax requests. 如果刷新页面,则一切正常,并且$.when正确执行ajax请求时有效。 However, if I deploy application, then the problem persists. 但是,如果我部署应用程序,则问题仍然存在。

Why, for the first time, is the ajax request already called (not in $,.when )? 为什么第一次已经调用了ajax请求(不在$,.when )? Where is my mistake? 我的错误在哪里? I have no errors in JavaScript. 我在JavaScript中没有错误。

If the code isn't any more complex than the example, you can do something like this 如果代码不比示例复杂,您可以执行以下操作

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() { ... });

I can't believe I suggested the following!! 我不敢相信我建议了以下内容! But I'm going to own it :D 但我要拥有它:D

One way to do what you want is with so called "lazy" promises 一种实现您想要的方式的方法就是所谓的“懒惰”承诺

a Promise/A+ polyfill - for Internet Explorer mainly (up to and including 11 - Edge, or whatever it's called in Windows 10, has native Promise) Promise / A + polyfill-主要用于Internet Explorer(不超过11​​-Edge,或者在Windows 10中称为它的任何东西,都具有本机Promise)

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

A lazy promise implementation, based on - https://github.com/then/lazy-promise - but modified to work with browser native promises - note, only tested in firefox, YMMV 一个基于-https: //github.com/then/lazy-promise的惰性承诺实现-但已修改为与浏览器本机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);
    };
}

Now to changes in your code - very minimal 现在要更改代码-非常少

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() { ... });

This is probably overkill, but it should do exactly what you requested in your question 这可能是矫kill过正,但它应该完全按照您的要求进行

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM