使用 jQuery.queue() 排队 ajax 请求

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4785724/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 17:56:00  来源:igfitidea点击:

Queue ajax requests using jQuery.queue()

jqueryajaxqueue

提问by MBax

I am using jQuery.queue() for the first time and haven't quite grasped it. Could someone please point out what I'm doing wrong?

我第一次使用 jQuery.queue() 并没有完全掌握它。有人可以指出我做错了什么吗?

Looking in firebug I am still seeing my POST requests firing at the same time - so I'm wondering if I'm calling dequeue() in the wrong place.

查看 firebug 我仍然看到我的 POST 请求同时触发 - 所以我想知道我是否在错误的地方调用了 dequeue() 。

Also - how can I get the queue length?

另外 - 我怎样才能得到队列长度?

The reason I need to queue these requests is that it gets fired on click of a button. And its possible for the user to click multiple buttons in quick succession.

我需要对这些请求进行排队的原因是单击按钮时它会被触发。并且用户可以快速连续单击多个按钮。

Tried to strip out the basic structure of my code:

试图剥离我的代码的基本结构:

$("a.button").click(function(){
   $(this).doAjax(params);
});

// method
doAjax:function(params){ 

   $(document).queue("myQueueName", function(){
     $.ajax({
       type: 'POST',
       url: 'whatever.html',
       params: params,
       success: function(data){
         doStuff;

         $(document).dequeue("myQueueName");
       }
     });
   });

}

回答by jAndy

You problem here is, that .ajax()fires an asyncronous running Ajax request. That means, .ajax()returns immediately, non-blocking. So your queue the functions but they will fire almost at the same time like you described.

这里的问题是,它.ajax()会触发异步运行的 Ajax 请求。这意味着,.ajax()立即返回,非阻塞。因此,您将功能排队,但它们几乎会像您描述的那样同时触发。

I don't think the .queue()is a good place to have ajax requests in, it's more intended for the use of fx methods. You need a simple manager.

我不认为这.queue()是一个放置 ajax 请求的好地方,它更适合用于fx methods. 你需要一个简单的经理。

var ajaxManager = (function() {
     var requests = [];

     return {
        addReq:  function(opt) {
            requests.push(opt);
        },
        removeReq:  function(opt) {
            if( $.inArray(opt, requests) > -1 )
                requests.splice($.inArray(opt, requests), 1);
        },
        run: function() {
            var self = this,
                oriSuc;

            if( requests.length ) {
                oriSuc = requests[0].complete;

                requests[0].complete = function() {
                     if( typeof(oriSuc) === 'function' ) oriSuc();
                     requests.shift();
                     self.run.apply(self, []);
                };   

                $.ajax(requests[0]);
            } else {
              self.tid = setTimeout(function() {
                 self.run.apply(self, []);
              }, 1000);
            }
        },
        stop:  function() {
            requests = [];
            clearTimeout(this.tid);
        }
     };
}());

This is far away from being perfect, I just want to demonstrate the way to go. The above example could be used in a way like

这离完美还很远,我只是想演示一下要走的路。上面的例子可以像这样使用

$(function() {
    ajaxManager.run(); 

    $("a.button").click(function(){
       ajaxManager.addReq({
           type: 'POST',
           url: 'whatever.html',
           data: params,
           success: function(data){
              // do stuff
           }
       });
    });
});

回答by diggersworld

I needed to do a similar thing so thought I'd post my solution here.

我需要做类似的事情,所以我想我会在这里发布我的解决方案。

Basically what I've got is a page which lists projects on shelves which all have distinctive criteria. I wanted to load the shelves one by one rather than altogether to get some content to the user quicker which they could look at whilst the rest loads.

基本上我得到的是一个页面,其中列出了货架上的项目,这些项目都有独特的标准。我想一个接一个地加载货架而不是全部加载,以便更快地向用户提供一些内容,他们可以在加载其余内容时查看这些内容。

Basically I stored the ID of each shelf in a JS array which I use when calling them from PHP.

基本上,我将每个架子的 ID 存储在我从 PHP 调用它们时使用的 JS 数组中。

I then created a recursive function which will pop the first index out of the array each time its called and request the shelf for the popped id. Once I have the response from the $.get()or $.post()whichever I prefer to use I then call the recursive function from within the callback.

然后我创建了一个递归函数,它会在每次调用时从数组中弹出第一个索引,并为弹出的 id 请求书架。一旦我得到了来自$.get()或者$.post()我更喜欢使用的响应,我就会从回调中调用递归函数。

Here's an elaboration in code:

这是代码中的详细说明:

// array of shelf IDs
var shelves = new Array(1,2,3,4);

// the recursive function
function getShelfRecursive() {

    // terminate if array exhausted
    if (shelves.length === 0)
        return;

    // pop top value
    var id = shelves[0];
    shelves.shift();

    // ajax request
    $.get('/get/shelf/' + id, function(){
         // call completed - so start next request
         getShelfRecursive();
    });
}

// fires off the first call
getShelfRecursive();

回答by Kim Jensen

I use this very simple code to keep ajax calls from "overtaking" each other.

我使用这个非常简单的代码来防止 ajax 调用相互“超越”。

var dopostqueue = $({});
function doPost(string, callback)
{
    dopostqueue.queue(function()
    {
        $.ajax(
        {   
            type: 'POST',
            url: 'thephpfile.php',
            datatype: 'json',
            data: string,
            success:function(result) 
            {
                dopostqueue.dequeue();
                callback(JSON.parse(result));
            }
        })
    });
}

If you don't want the queue to handle itself, you can just remove the dequeuefrom the function and call it from another function. As to getting the queue length, for this example it would be:

如果您不希望队列自行处理,您可以dequeue从函数中删除并从另一个函数调用它。至于获取队列长度,对于这个例子,它将是:

dopostqueue.queue().length

回答by Suing

you could extend jQuery:

你可以扩展jQuery:

(function($) {
  // Empty object, we are going to use this as our Queue
  var ajaxQueue = $({});

  $.ajaxQueue = function(ajaxOpts) {
    // hold the original complete function
    var oldComplete = ajaxOpts.complete;

    // queue our ajax request
    ajaxQueue.queue(function(next) {    

      // create a complete callback to fire the next event in the queue
      ajaxOpts.complete = function() {
        // fire the original complete if it was there
        if (oldComplete) oldComplete.apply(this, arguments);    
        next(); // run the next query in the queue
      };

      // run the query
      $.ajax(ajaxOpts);
    });
  };

})(jQuery);

then use it like:

然后像这样使用它:

$.ajaxQueue({
    url: 'doThisFirst.php',
    async: true,
    success: function (data) {
        //success handler
    },
    error: function (jqXHR,textStatus,errorThrown) {
        //error Handler
    }       
});
$.ajaxQueue({
    url: 'doThisSecond.php',
    async: true,
    success: function (data) {
        //success handler
    },
    error: function (jqXHR,textStatus,errorThrown) {
        //error Handler
    }       
});

of course you can use any of the other $.ajax options like type, data, contentType, DataType since we are extending $.ajax

当然,您可以使用任何其他 $.ajax 选项,如类型、数据、内容类型、数据类型,因为我们正在扩展 $.ajax

回答by David Woakes

I needed to do this for an unknown number of ajax calls. The answer was to push each into an array and then use:

我需要为未知数量的 ajax 调用执行此操作。答案是将每个推入一个数组,然后使用:

$.when.apply($, arrayOfDeferreds).done(function () {
    alert("All done");
});

回答by Guy Bedford

I found the above solutions kind of complicated, plus I needed to alter the request just before sending (to update a fresh data token).

我发现上述解决方案有点复杂,而且我需要在发送之前更改请求(以更新新的数据令牌)。

So I put this one together. Source: https://gist.github.com/2470554

所以我把这个放在一起。来源:https: //gist.github.com/2470554

/* 

Allows for ajax requests to be run synchronously in a queue

Usage::

var queue = new $.AjaxQueue();

queue.add({
  url: 'url',
  complete: function() {
    console.log('ajax completed');
  },
  _run: function(req) {
    //special pre-processor to alter the request just before it is finally executed in the queue
    req.url = 'changed_url'
  }
});

*/

$.AjaxQueue = function() {
  this.reqs = [];
  this.requesting = false;
};
$.AjaxQueue.prototype = {
  add: function(req) {
    this.reqs.push(req);
    this.next();
  },
  next: function() {
    if (this.reqs.length == 0)
      return;

    if (this.requesting == true)
      return;

    var req = this.reqs.splice(0, 1)[0];
    var complete = req.complete;
    var self = this;
    if (req._run)
      req._run(req);
    req.complete = function() {
      if (complete)
        complete.apply(this, arguments);
      self.requesting = false;
      self.next();
    }

    this.requesting = true;
    $.ajax(req);
  }
};

回答by Jeaf Gilbert

Another version of jAndy's answer, without timer.

jAndy 答案的另一个版本,没有计时器。

var ajaxManager = {
    requests: [],
    addReq: function(opt) {
        this.requests.push(opt);

        if (this.requests.length == 1) {
            this.run();
        }
    },
    removeReq: function(opt) {
        if($.inArray(opt, requests) > -1)
            this.requests.splice($.inArray(opt, requests), 1);
    },
    run: function() {
        // original complete callback
        oricomplete = this.requests[0].complete;

        // override complete callback
        var ajxmgr = this;
        ajxmgr.requests[0].complete = function() {
             if (typeof oricomplete === 'function')
                oricomplete();

             ajxmgr.requests.shift();
             if (ajxmgr.requests.length > 0) {
                ajxmgr.run();
             }
        };

        $.ajax(this.requests[0]);
    },
    stop: function() {
        this.requests = [];
    },
}

To Use:

使用:

$(function() {
    $("a.button").click(function(){
       ajaxManager.addReq({
           type: 'POST',
           url: 'whatever.html',
           data: params,
           success: function(data){
              // do stuff
           }
       });
    });
});

回答by Epoc

The learn.jquery.com website have a good example too:

learn.jquery.com 网站也有一个很好的例子

// jQuery on an empty object, we are going to use this as our queue
var ajaxQueue = $({});

$.ajaxQueue = function(ajaxOpts) {
  // Hold the original complete function
  var oldComplete = ajaxOpts.complete;

  // Queue our ajax request
  ajaxQueue.queue(function(next) {
    // Create a complete callback to invoke the next event in the queue
    ajaxOpts.complete = function() {
      // Invoke the original complete if it was there
      if (oldComplete) {
        oldComplete.apply(this, arguments);
      }

      // Run the next query in the queue
      next();
    };

    // Run the query
    $.ajax(ajaxOpts);
  });
};

// Get each item we want to copy
$("#items li").each(function(idx) {
  // Queue up an ajax request
  $.ajaxQueue({
    url: "/ajax_html_echo/",
    data: {
      html: "[" + idx + "] " + $(this).html()
    },
    type: "POST",
    success: function(data) {
      // Write to #output
      $("#output").append($("<li>", {
        html: data
      }));
    }
  });
});

回答by Nibbels

Here is my solution, which I use to produce a queue of requests for some Browsergame. If anything happens I stop this queue and finish the work with some special last request or cleanup.

这是我的解决方案,我用它来为某些 Browsergame 生成请求队列。如果发生任何事情,我会停止此队列并通过一些特殊的最后请求或清理来完成工作。

var get_array = ["first", "second", "third"];

var worker = $("<div />"); // to line up requests in queue
$.queuedAjax = function(args){  // add up requests for me       
    worker.queue(
        function(next){
            $.ajax(args).always(next);            
        }
    );
  };

$.queuedSomething = function(){ // add up something special for me
    worker.queue(
        function(next){
            //worker.clearQueue();
            //worker = $("<div />"); //cleanup for next .each
            //maybe another .each           
        }
    );
  };

$.each( get_array , function( key , value ) {
  $.queuedAjax({
    type: 'GET',
    url: '/some.php?get='+value,
    dataType: 'text',
    success: function(sourcecode){

        if (sourcecode.match(/stop your requests, idiot!/)) {   
            worker.clearQueue().queue($.queuedSomething);
            alert(' the server told me to stop. i stopped all but not the last ′$.queuedSomething()′ ');
        }

    }
  });           
}); 
$.queuedSomething();

回答by Pow-Ian

I also had to do this within a solution i had and I found I could do it this way:

我还必须在我拥有的解决方案中执行此操作,并且我发现我可以这样做:

//A variable for making sure to wait for multiple clicks before emptying.
var waitingTimeout; 

$("a.button").click(function(){
   $(this).doAjax(params);
   clearTimeout(waitingTimeout);
   waitingTimeout = setTimeout(function(){noMoreClicks();},1000);
});

// method
doAjax:function(params){ 

   $(document).queue("myQueueName", function(next){
     $.ajax({
       type: 'POST',
       url: 'whatever.html',
       data: params,
       contentType: "application/json; charset=utf-8",
       dataType: "json",
       success: function(data){
         doStuff;
         next();
       },
       failure: function(data){
         next();
       },
       error: function(data){
         next();
       }
     });
   });

}

function noMoreClicks(){
    $(document).dequeue("myQueueName");
}

by using the next()callback that is passed in the queue function you can dequeue the next operation. So by putting the next in the handlers for the ajax, you effectively make the ajax calls asynchronous to the browser and the render or paint thread of the browser, but make them synchronous or serialized to each other.

通过使用next()在队列函数中传递的回调,您可以使下一个操作出列。因此,通过将 next 放在 ajax 的处理程序中,您可以有效地使 ajax 调用与浏览器和浏览器的渲染或绘制线程异步,但使它们彼此同步或序列化。

Here is a very basic example.In the example fiddle. Click the button once and wait a second. You will see that the time out triggers and the single operation happens. Next click the button as fast as you can (or faster than one second) and you will see that all the times you click the button, the operations are queued and then only after waiting a second do they hit the page and fade in one after the other.

这是一个非常基本的例子。在示例小提琴中。单击一次按钮并稍等片刻。您将看到超时触发和单个操作发生。接下来尽可能快地点击按钮(或快于一秒),你会看到你点击按钮的所有时间,操作都在排队,然后只有等待一秒钟后它们才会点击页面并在一个之后淡入另一个。

The beauty of this is that if the queue is already emptying, any operations you add to it while it is emptying are placed on the end and then just processed when the time comes.

这样做的好处是,如果队列已经排空,那么在排空时添加到它的任何操作都会放在最后,然后在时间到来时才进行处理。