12

I have many asynchronous AJAX calls whose results will get processed. It doesn't matter what order the processing occurs, but the results need to get processed one at a time. So I'd like to simple do my AJAX calls and they all just put their results in a single queue. That queue should then get processed on a single thread. This way the results get processed one at a time as soon as possible.

What's the best way to do this? I'm using jQuery, so happy to take advantage of any facilities it provides for this.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
at.
  • 50,922
  • 104
  • 292
  • 461
  • You could just use $.when(promiseArray).done(function (result1, result2, etc..) { all calls complete, process all of it now }); – Shane Jul 11 '18 at 01:23

4 Answers4

27

Asynchronous does NOT mean 'multiple threads'. Think about many click events firing in a row, before the first click handler is processed. Only one action can be handled at a time, and the others will wait to execute.

Event driven languages like Javascript operate on the basis of a queue. Javascript in the background essentially has one giant queue that events and asynchronous responses get pushed in to. Once a particular piece of processing is complete, the next item from the queue is worked on.

These queues are sometimes known as 'Runloops'. Javascript will spin in an endless loop, retrieving an event from the queue, processing it, and returning back to the queue for another piece of work.

Multithreading can be achieved in (newer) versions of Javascript using Web Workers, but these are explicitly opt-in. Look them up if you're interested.

To answer your question then, just attach a callback to your asynchronous request, and it will complete processing even if another response is returned half way through. The other response will 'wait' until the current event is handled.

blong
  • 2,815
  • 8
  • 44
  • 110
Josh Smeaton
  • 47,939
  • 24
  • 129
  • 164
  • 6
    I think everyone is overcomplicating the question because it used the word 'threads'. I believe OP simply means that he needs each callback to fully complete before the next one starts. I'm assuming because jQuery is involved this is because some kind of animation is occurring, which will use timers and therefore appear multi-threaded (two callbacks can seem to be running at the same time). – beeglebug Jan 17 '11 at 10:25
  • @beeglebug - I don't believe you're right. The OP explicitly states " It doesn't matter what order the processing occurs". It's a common misconception that asynchronous means multithreading, and I believe the OP was under this same impression. – Josh Smeaton Jan 17 '11 at 10:46
  • @Josh Smeaton - Possibly, but we could with OP himself coming back and shedding some light. It all comes down to whether 'processing' means raw number crunching or something more UI based. And with jQuery involved (and from glancing at OP's question history) i'm thinking it's UI/animation. – beeglebug Jan 17 '11 at 11:11
  • 1
    I really don't believe it matters either way. Once the first response returns, it can add an animation event to the queue. The second responds, and adds its animation event to the queue. Then the first animation event fires, and then the second. The processing is irrelevant. Understanding event-based programming in Javascript is what matters IMO. – Josh Smeaton Jan 17 '11 at 11:21
  • @Josh - That's not really how animations work in jQuery. An animation is not a discreet function call, it is a sequence of function calls triggered by setTimeout or setInterval, which can and will overlap all over the place. – beeglebug Jan 17 '11 at 12:14
  • @beegle, jQuery uses it's own animation queue, and unless the speed is changed on an animation, they will execute in an approximate order. I'm aware that they are not function calls. They are events set to run on the message loop. Usually these are executed in order though. Your answer does nothing to force order. If new events are generated after the handler, it will still return and exit the `processing` block, allowing any items on the stack to begin before any potential new events have completed. – Josh Smeaton Jan 17 '11 at 12:29
  • @beeglebug: That's not how setTimeout and setInterval work in javascript. They merely queue discreet function calls. There is nothing special and the function calls cannot overlap. – slebetman Jan 17 '11 at 13:00
  • @Josh: On the contrary, they are function calls. Just ones triggered sequentially by timed events. – slebetman Jan 17 '11 at 13:01
  • 1
    @beeglebug: Upon reading further your answer I see what you mean by overlap. So ignore my comments above. Still, the OP doesn't mention weather or not he cares if any animations run in parallel. He's just worried if he needs to use a mutex or semaphore and presumably can't find them in javascript. – slebetman Jan 17 '11 at 13:04
  • @slebetman - I agree (and i'm glad someone finally took the time to understand what I was trying to say!). I just jumped in with a quick and simple answer (lured by the mention of jQuery), and somehow it devolved into an argument around the technicalities of "overlapping" code. – beeglebug Jan 17 '11 at 16:04
  • @beegle, 'discussion' not 'argument' =) – Josh Smeaton Jan 17 '11 at 21:06
  • @beeglebug I've come across this thread a few times and have meant to apologise - so I apologise. I didn't take the time to understand what you were saying, but your message was right. – Josh Smeaton Sep 23 '14 at 07:03
5

If your only concern is the browser (since you mention jQuery, I assume that's true), you should know that Javascript is single-threaded in browsers.

Community
  • 1
  • 1
Kyle Wild
  • 8,845
  • 2
  • 36
  • 36
  • 2
    Wow, I was unaware of this and seems strange... so I can make 100 AJAX requests, and it does seem that these requests are asynchronous and on separate threads, and the callback functions will be called one at a time? – at. Jan 17 '11 at 09:12
  • @dorktitude - Actually, JavaScript is now multi-threaded, thanks to WebWorkers: https://developer.mozilla.org/En/Using_web_workers – jamesmortensen Jan 17 '11 at 09:26
  • @jmort253 It's correct that multi-threaded stuff can now be done *intentionally* in some browsers, but to my knowledge it doesn't happen accidentally (i.e. in the OP's question, no special precautions need be taken to make the queue thread safe) – Kyle Wild Jan 17 '11 at 09:35
  • async queries in jQuery means that your code makes no pause after you call the query, but the XmlHttpRequest will treate each request one after the other, check http://stackoverflow.com/questions/1060539/parallel-asynchronous-ajax-requests-using-jquery where people are trying to enforce a real parallelisation, that means by default your queries are queued (but you can try to use jQuery.queue if you fear it won't ba always like that). – regilero Jan 17 '11 at 12:49
  • 3
    It should be noted that even with web workers there is no need to worry about code running in parallel since web workers cannot share variables with either the main thread or with each other. Each web worker is essentially a single-threaded event loop and you communicate with them with something that resembles ajax calls. Think of them as servers - running on the browser. They are not your traditional threads. – slebetman Jan 17 '11 at 13:11
1

You might want to take a look at Event messaging between JavaScript objects.

I used an implementation similar to the blog post with a jQuery Plugin called ajaxMonitor.

The way it works as soon as any of the callbacks from the AJAX request get called it updates a HTML table. The callbacks happen asynchronous.

The very nature of AJAX means asynchronous. So processing your QUEUE in the success callback of your AJAX request, I believe would accomplish what your looking for.

Gutzofter
  • 2,003
  • 23
  • 26
0

The simplest way would be to implement your own queue system for the callbacks (using push/pop to emulate a stack).

As each asynchronous request returns, add the data to the end of an array and fire off some kind of queue.process() command, which would handle the first element in the array.

Finally, add something like if(alreadyRunning) { return; } to the top of that function to stop it doing more than one at once, and you've got your single threaded queue.

edit: removed code, some people were getting hung up on it instead of the original question

beeglebug
  • 3,522
  • 1
  • 23
  • 39
  • The only time that there will be multiple items in your queue is if the `this.handler(item)` pushes another workitem onto the stack. There is absolutely no need for this, as most asynchronous calls are able to accept callbacks for when they complete. – Josh Smeaton Jan 17 '11 at 10:05
  • I thought the idea was that some external code would be firing off ajax calls, and using `queue.add` as the callback. That way the return data would be added to the queue, and if a second piece of data was returned while the first was being processed, it would get added to the queue to be processed once the first was finished. – beeglebug Jan 17 '11 at 10:11
  • Impossible. Another piece of data returning can NOT be executed while the first is still processing. It will wait until the only thread becomes 'free' to do the work. The `queue.add` is redundant. Just attach the handler directly to each asynchronous request. – Josh Smeaton Jan 17 '11 at 10:51
  • Possible! :) It just depends entirely on what you mean by 'processed'. If animation is involved (fading in some text, rolling out a hidden element), and two callbacks come in close to each other, the animations could easily overlap. – beeglebug Jan 17 '11 at 11:08
  • @beeglebug: Impossible. Any piece of animation code will not run while an ajax callback is running. Similarly, any piece of ajax callback will not run while an animation tweening function is running. setTimeout and setInterval is not magical. They don't spawn threads. They just queue events. – slebetman Jan 17 '11 at 12:56
  • @beeglebug: `the animations could easily overlap` You seem to be under the impression that this is possible in javascript in the browser. It is not. – slebetman Jan 17 '11 at 12:57
  • I know technically no two bits of code are running at the same time, but I never claimed they were. I simply mentioned that by using timers and such (as jQuery animations do) two discreet blocks of code can SEEM to be running simultaneously, which they can, I do it every day on the sites I develop. I know it's all smoke and mirrors when you get down to the metal, but it's close enough for the client! – beeglebug Jan 17 '11 at 15:57