I have a number of async calls being made in JavaScript. I would like to ensure that only a single async call is in flight at any one time. How can I achieve this?
Does the Q library expose something relevant to this?
It depends if you want to retain all calls or discard any calls made while one is in-flight.
If you want to retain all calls, you shouldn't make the Ajax calls directly, but rather put them in a queue. The queue abstraction would then be responsible for making the Ajax calls, using a lock variable to check if one is already in-flight. When an Ajax call is received or timed out, it can trigger the queue to check for any pending calls so the next one can be fired off.
If you want to discard calls made while one is in-flight, a simple lock mechanism would do. For any call, just check if the lock is true and if not, fire the request and set the lock to true. If the lock is true, do nothing (discard it). Clear the lock when the call is received or times out.
I'm not a Q user, but Q is essentially a library implementing promises, so you can ensure this by chaining a series of .then clauses together, each one containing one call, or launching the next call from the .done operation of the previous AJAX call.
What i can think of is using a functions queue to process ajax functions based on the result of jQuery.active which counts the active ashync calls.
So when calling an ajax function check for the active ajax running, if it is 1 then add your function to the queue, other wise execute it.
You can then use the ajaxStop function to trigger any remaining function to be called within the queue, call the function and remove it from queue.
In this way you will ensure that a single ajax call runs. This is just some brainstorming, I haven't tested the exact behavior but this approach might help.
Related
So I kind of understand the JS event loop, but still have a few questions. Here is my scenario and a few questions.
So let's say I have these functions:
function1 - reads an absolute huge file.
function2 - console.log("Hey");
function3 - console.log("What's up");
The way I am understanding this, and correct me if I'm wrong, what would happen is that the function1, function2, and function3, would be added to the queue. Then function1 would be added to the call stack followed by the next two functions.
Now the part where I'm confused is because the first function is going to take an extremely long time what happens to it? Does it get pushed somewhere else so that the next two functions are executed? I think the answer to this is that the only way it gets pushed somewhere else so that you can continue running is to make it an asynchronous function. And the way you make it a asynchronous function is either by using a callback function or promises. If this is the case how does it know that this is a asynchronous function? And where does it get pushed to so that the other two functions can be executed since they are relatively simple?
I think I answered the question myself but I keep confusing myself so if somebody could explain in extremely simple terms that would be great and sorry for the extremely stupid question.
Ordinary function calls are not pushed on the event queue, they're just executed synchronously.
Certain built-in functions initiate asynchronous operations. For instance, setTimeout() creates a timer that will execute the function asynchronously at a future time. fetch() starts an AJAX request, and returns a promise that will resolve when the response is received. addEventListener() creates a listener that will call the function when the specified event occurs on an element.
In all these cases, what effectively happens is that the callback function is added to the event queue when the corresponding condition is reached.
When one of these functions is called, it runs to completion. When the function returns, the event loop pulls the next item off the event queue and runs its callback, and so on.
If the event queue is empty, the event loop just idles until something is added. So when you're just starting at a simple web page, nothing may happen until you click on something that has an event listener, then its listener function will run.
In interactive applications like web pages, we try to avoid writing functions that take a long time to run to completion, because it blocks the user interface (other asynchronous actions can't interrupt it). So if you're going to read a large file, you use an API that reads it incrementally, calling an event listener for each block. That will allow other functions to run between processing of each block.
There's nothing specific that identifies asynchronous functions, it's just part of the definition of each function. You can't say that any function that has a callback argument is asynchronous, because functions like Array.forEach() are synchronous. And promises don't make something asychronous -- you can create a promise that resolves synchronously, although there's not usually a point to it (but you might do this as a stub when the caller expects a promise in the general case). The keyword async before a function definition just wraps its return value in a promise, it doesn't actually make it run asynchronously.
I have a an angular event like this:
$rootScope.$broadcast("postData");
doSomething();
however, doSomething() must wait for postData to complete before execution.
I would normally do something like:
$rootScope.$broadcast("postData").then(function(){
doSomething();
});
But apparently this isn't a thing in angular...Any ideas?
I would like to point-out that the previous solutions are not possible to be implemented where we don't have a handle on the async call to put a callback/promise/throw an event to solve the issue. The async call may be library function like for example setTimeout and we just cant use the previous solutions to fix the flow.
Here's my solution:
Put doSomething(); in an setTimeout with the time interval set to 0,
$rootScope.$broadcast("postData");
setTimeout(function(){
doSomething();}
, 0);
As simple as that!
settimeout makes dosomething() also to be asynchronous and this makes both the asynchronous operations happen one after the other(asynchronously). How? The explanation follows, but first note that the dosomething() is in a setTimout of interval 0 ms. One may obviously think that dosomething() shall be executed right-away (after 0 ms (actually default minimum time interval in javascript is 4 ms, so 0 ms becomes 4 ms)) before the postData event is broadcast-ed and serviced.
The answer is no!
Settimeout doesn't guarantee that the callback function passe inside it shall surely get executed after the specified interval. The specified interval is just the minimum interval needed after which the callback can be executed. SetTimeOut is an asynchronous call. if there are any other async operation waiting in the pipeline already, javascript runs them first.
For understanding how all this happen you need to understand what is an event loop in javascript.
Javascript runtime is single threaded, it just have one call stack, meaning it runs the code sequentially as it is written. Then how on earth does it implement asyncronicity?
So this is what happens under the hood when the javascript run-time encounters an operation that is asyncronous (like an API call, http call, settimeout, event broadcast etc). Please note these functions are not provided in our native javascipt run time engine (for example chromes V8 engine), instead they are provided by the browser (known as webAPIs), which are basically threads that you can make call to and they fork off an independent path of execution, separate from the javascript run-time execution flow, and thats how concurrency is actually achieved.
The question arises that Javascript run time is still single threaded. So how does these webAPI inturrpt the runtime flow and provide their results when they are complete? They can not just prompt the javascript runtime anytime when they are finished and provide their results to it? There must be some mechanism.
So javascript just makes the call to these webAPI's and does not wait for the output of the call. It simply goes on and execute the code that follows the call, and thats how the dosomething() in the problem, gets executed before the postDate event is listened and served).
Meanwhile the forked thread processes the http call or the setTimeout or handle the event etc, whatever the async call was made for. And when its done, the callback is pushed onto a event queue (task queue) (Note that multiple callback returns can be pushed into this queue.). But they are not run right away.
The javascript runtime waits for the call stack to get empty first. When there is nothing for the javascript runtime to execute the async calls callback function are popped out from the task queue, one by one and executed.
So in essence if we can just make dosomething() async, it will get executed after the 1st async is completed. Thats what I did. The settimeout callback gets pushed onto the event queue/task queue. Javascript call stack gets empty. The call back for postData event broadcast gets served. Then dosomething() gets a chance to execute.
You could $broadcast the event, listen for it in your other controller with $on, and $emit another event on completion, and listen for it in your original controller so you know when it is finished.
I would not recommend this approach. Instead use a service.
Emit and broadcast are coupling your mechanisms for communication to the view because the $scope is fundamentally a fabric for data-binding.
The services approach is far more maintainable and can communicate between services in addition to controllers.
Im assuming the broadcast of 'postData' is defining the end of a funciton.
If you use the $q angular service this can be accomplished easily by creating asynchronous functions.
function postData() {
var deferred = $q.defer();
//Do your asynchronous work here that post data does
//When the asynchronous work is done you can just resolve the defer or
//you can return data with resolve. Passing the data you want
//to return as a param of resolve()
deferred.resolve();
//return
return deferred.promise;
}
When you call postData now you can now use the then method to run doSomething() after postData() is done.
postData().then(function(data) {
doSomething();
}, function (err){
//if your ansyncronous function return defer.reject() instead of defer.resolve() you can catch the error here
};
Heres the angular documentation for $q
Heres a plunk to show you a simple example
This isn't how events works, you can't wait for events to complete.
Why won't you fire 'postData', let the consumers of this event do whatever they does, and then wait for another event and execute 'doSomething' once you receive it?
This way, once the consumer of 'postData' finish processing the event, he can fire another event which you can consume and execute your 'doSomething' when you receive it.
"When there's nothing to do, check the queue. But only check the queue
when there's nothing left to do."
~ Javascript (https://www.youtube.com/watch?v=vMfg0xGjcOI)
So from what I understand, it basically means that you're delaying execution. Something like
SomeAsynchronousFunction();
SomeRegularFunction();
SomeOtherRegularFunction();
just means that you're essentially rearranging the tasks to
SomeRegularFunction();
SomeOtherRegularFunction();
SomeAsynchronousFunction();
in terms of how the bodies of the three functions are executed. Except that, if your browser/hardware supports parallel computing, and if the body of SomeAsynchronousFunction does not have any dependency on the other two functions, that it will be executed in parallel with the other two functions. Is that right? Or am I totally confused?
You're pretty close. But usually there will be some parts of SomeAsynchronousFunction that are synchronous, and those will be executed immediately -- it's only the completion of the function that's async. For instance, it might perform an AJAX call, so it first creates the XHR object, collects the parameters into a FormData object, and calls xhr.send() immediately; the asynchronous part is the execution of the onreadystatechange callback function, which happens when the server responds and the event processing loop has nothing else to do. So the actual order of execution is like this:
synchronous parts of SomeAsynchronousFunction();
SomeRegularFunction();
SomeOtherRegularFunction();
callback function from SomeAsynchronousFunction();
Javascript runs on a single thread, is non-blocking and uses what's called an event loop so your functions run in the original order, but the asynchronous calls, when they return add another message to the event loop and get executed when all other preceeding messages in the event loop are processed. For more info, I recommend reading this article from the Mozilla Developer Network, Concurrency model and Event Loop
I’ve been reading about callback functions here, and learned that JavaScript is a single-thread synchronous language.
This means that if you want to collect data from a database then you’d have to wait for the routine to finish before any more code was executed. Is this true? What would happen if the user pressed a button to call a different function in the same script file?
To make it asynchronous you can use callbacks. Asynchronous here would mean that a section of code in the callback would ‘wait’ for an event before being called but a new thread is not created.
What is it about being an Object that makes JavaScript callbacks asynchronous?
It is the same as waiting for an event?
It is true that with Javascript, if you are going to call into a database, generally you must wait for the database to respond (ie, a round trip to Pluto) before your code will continue to execute. This is called a 'blocking' call.
What a callback allows you to do is make a blocking call, but as you do so also say, "Execute this code when the blocking call concludes, but don't wait around for that to happen." Thus, your program continues execution. When the blocking call completes, the code you specify in the callback (which has not been run yet) will then execute. This may be almost immediately or some time later.
With Javascript, the rest of your code will complete execution, then the first callback to be triggered by a blocking call finishing will be executed, and so on until all callbacks are executed. At that point the thread will be shut down.
Note that only the callback code is 'waiting for an event'.
Thus, the execution order looks something like this:
Execute some code.
Set up callback code.
Execute blocking call.
Execute remainder of code.
Wait for blocking call to return.
Execute callback code.
Stop thread process.
i'm not sure this is possible.
I have two ajax calls executed during a button click event.
first ajax call is to add data to database using jquery ajax post .
the second one is to add another set of data to database too via jquery ajax post too
The first one will execute first then the second one. i have set a timer to the second call(windowstimeout) to create a time interval between both execution to test if i can pause the first ajax call.
You will be asking me why i don't want to combine both calls. i have the reasons to do, and i want to know is it really possible to pause an ajax call. I have search around the net , all i found is the ajaxstop(jQuery) but it don't really pause it , it stops the ajax call.
SO anyone have any idea to do so? Thanks.
Why do you want to pause it? You can't, but why would you want to? Just let them both run, or don't trigger the first call till the second is done.
No, you cannot pause Ajax calls - they are just instances of the normal HTTP request/response cycle and behave as such. If the server-side operations resulting from the second call depend on the results of the first one, then why don't you just chain the calls and trigger the second one in the first's success callback handler?
You cannot do that.
You should really ask yourself if the design of your data exchange protocol is correct.
Pausing a request (whatever the communication protocol is, AJAX or any other) should not work since you cannot know if there are other requests and what they do.
So ask yourself the questions: what is my exact need ? what are the other ways to do that ?