Why is AJAX called asynchronous? How does it accomplish communication asynchronously with the server?
It's asynchronous in that it doesn't lock up the browser. If you fire an Ajax request, the user can still work while the request is waiting for a response. When the server returns the response, a callback runs to handle it.
You can make the XMLHttpRequest synchronous if you want, and if you do, the browser locks up while the request is outstanding (so most of the time this is inappropriate)
It's asynchronous because the client and the server run independently of each other for the duration of the function call.
During a normal function call, you make the call, and the calling function doesn't get to execute again until the function call finishes and returns. The caller and the callee are always synchronized.
During an asynchronous function call, you make the call, and then control returns immediately to the caller. The callee then returns a value some indeterminate amount of time later. That "indeterminate amount of time" means the caller and callee are no longer synchronized, so it's asynchronous.
Simply put, it does not need to reload the whole page to get new information.
Think of a email client. You would not need to refresh the page to see new emails. Ajax just pulls the server every couple of minutes to see if there are new emails, if so display them
I.e. not "blocking", within the context of Javascript execution, as the response will be handled by an event loop.
The client and the server run independently of each other for the duration of the function call.
Normal function call - you make the call, and the calling function doesn't get to execute again until the function call finishes and returns. The caller and the callee are always synchronized.
Asynchronous function call - you make the call, and then control returns immediately to the caller. The callee then returns a value some undefined amount of time later. That "undefined amount of time" means the caller and callee are no longer synchronized, so it's asynchronous.
Synchronous always maintain sequence when called, but asynchronous is not maintain sequence.
Related
Suppose we have a look like this:
documents.forEach(url=>{
await fetch(url).
then(
document=>
console.log(document);
}
Will this load all the documents in parallel, or will the documents be loaded in serial?
In other words we could push the fetch promises into an array and then call Promise.all on that array which will execute all the promises in parallel.
IIUC there is no difference really except the Promise.all will fail on the first failure of a fetch request.
Provided the callback function is declared as async, then await can be used:
documents.forEach(async url => {
await fetch(url).then(console.log);
}
The sequence of execution is then as follows:
The forEach method is executed.
This includes calling the callback for each url, which happens one after the other
One execution of the callback will call fetch, which launches the HTTP request and returns immediately with a promise. In the background the non-JavaScript, lower-level API polls for the HTTP response to come in. Only that background part happens in parallel with the steps described here.
The then method is executed and the callback passed to it is registered. The then method immediately returns a promise
The await kicks in: the callback function's execution context is saved and it exits, returning a promise which this code ignores.
The next iteration takes place, repeating from step 3.
The forEach method ends. At this stage there are several non-JavaScript threads polling for HTTP responses, and there are several JS execution contexts pending for later execution.
In some unpredictable order (depending on the response time of the server giving the response), the fetch API resolves the promise that it had returned, and puts a message in the Promise Job Queue to indicate that.
The JavaScript event loop detects the event and proceeds with the execution of the callback registered in step 4 (the then callback), outputting to the console. The promise that was returned by the then method is resolved, which puts a new message in the Promise Job Queue.
The message is pulled from the queue and this will restore the corresponding execution context of the forEach callback. The execution continues after the await, and as there is nothing more to execute, the promise returned in step 5 is resolved (but no-one listens to that)
JavaScript monitors the event queue for more such work, and will at some point repeat at step 8.
No JavaScript code executes in parallel with JavaScript here, but the fetch API relies on non-JavaScript code, reaching "down" into Operating System functions, which do run in parallel with JavaScript code (and other OS functions).
Also note that the code is very similar to this non-async/await variant:
documents.forEach(url =>
fetch(url).then(console.log)
);
...because this callback also returns a promise. Except for the "saving execution context" part, which is not taking place here, the execution plan is quite similar.
I am currently learning firebase and I am trying to trigger an asynchronous Api call as part of a http trigger.
In the docs it says:
Resolve functions that perform asynchronous processing by returning a JavaScript promise.
Terminate HTTP functions with res.redirect(), res.send(), or res.end().
Terminate a synchronous function with a return; statement.
So what method could I use to make the network call without falling foul of the 60s limit - can I extend this?
Currently just calling to the network will occasionally time out as it goes over the 60s limit.
If your HTTPS trigger is always timing out, that means you aren't fully following the advice of the documentation you cited and always returning a response to the client.
If your HTTPS trigger simply takes over a minute to complete, and you need more time, you can increase the timeout in the Cloud console.
Let's say I have a function that does a standard AJAX request:
function doXHR() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts');
xhr.send();
xhr.onreadystatechange = () => {
console.log('ready state change');
};
}
doXHR();
console.log('done');
This code will cause the browser to start an AJAX request, but at what point in the function does the request actually start? According to this post: https://blog.raananweber.com/2015/06/17/no-there-are-no-race-conditions-in-javascript/
[Calling xhr.onreadystate() after send()] is possible, because the HTTP request is only executed after the current scope has ended its tasks. This enables the programmer to set the callbacks at any position he wishes. As JavaScript is single-threaded, the request can only be sent when this one single thread is free to run new tasks. The HTTP request is added to the list of tasks to be executed, that is managed by the engine.
But when I add a breakpoint in devtools right after the send call:
I do get a network request, albeit in a pending state:
At the breakpoint, the XHR's readystate is 1, which is XMLHttpRequest.OPENED. According to MDN's documentation, XMLHttpRequest.OPENED means that xhr.open() has been called: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState
But if I comment out xhr.send() so that only .open() is called:
Then I get no pending network request:
Thinking that perhaps I need the function scope to end in order for the request to actually be sent out, I moved the breakpoint to after the function call (and modified the code a bit to see the XHR readyState):
But I still get the pending network request:
It seems like the debugger not only freezes code execution, but also any network requests. This makes sense, as you don't want network requests to complete while you're on a breakpoint, but this also makes it impossible to tell when the network request is actually initiated.
My question is, at what point does the request actually get sent out? Does calling xhr.send() merely set up the request, but requires that the function scope end before the request is initiated? Does xhr.send() immediately initiate the request before the function scope ends? Or is there something else going on here?
send immediately initiates the request. This is at least hinted at by MDN's documentation for send.
The author of the blog you link to is correct that there are no race conditions per-se, but that does not keep you from having things happen out-of-order. An example of this would be if you load multiple <script> tags in with the async=true set on them. In this case, if one script depends on the other, you could end up in a situation where you have an unpredictable sequence of events (which is very similar to a race condition) because two asynchronous events finish at different times.
It is true that you can set onreadystatechange after calling send because even if the request request failed immediately, the event won't get dispatched until the function scope completes. The delay here is not in the dispatching of the network request, but in the dispatching of the event to say that the network request completed.
It is important to note, that networking itself is not handled in JavaScript, but rather by the browser implementation, which is native code, and could be multi-threaded (although I do not know if it is). This means that the browser is perfectly capable of handling network tasks while your javascript is running.
I'm trying to send a file in chunks over WebRTC, and I'm wondering if I can create a callback function to be called after RTCDataChannel.send() finishes sending each chunk of the file.
Is RTCDataChannel.send() a synchronous/blocking call? If so, my callback can be executed on the line after .send().
If .send() is asynchronous/non-blocking, then this will get tricky since it doesn't seem like .send() accepts a callback function, and I want to avoid using a buffer and a timeout.
The send method is blocking. It however doesn't wait until the data went over the wire, but only puts the data on an internal buffer from where it might later (or in parallel to the script execution) be sent.
The amount of data that has not been transmitted is available as the bufferedAmount property, which will be synchronously increased by every send() call (and not be updated otherwise until the next event loop turn).
You might make your wrapper asynchronous therefore, and put a timeout before actually calling send() when the currently buffered data is "too much" (by whatever criterion you see fit).
As noted above send() is effectively async - you don't get delivery receipt.
However there is a callback onbufferedamountlow which is invoked when
the channel drains it's send buffer below a value set with bufferedAmountLowThreshold
(see MDN onbufferedamountlow)
You can use that callback to decide when to send the next chunk.
Note however that this is relatively new to the draft standard and may not be supported everywhere.
I have written a JavaScript function that asynchronously calls a web service using XmlHttpRequest. I have been asked to make this function finish its work before the page is rendered.
I thought I could make the AJAX request synchronous but I don't want this to make the page hang too long - I'd like to abort the request after, say, 1 second if a response isn't received.
Is it possible to abort a synchronous XmlHttpRequest?
You can't:
http://www.hunlock.com/blogs/Snippets:_Synchronous_AJAX sais:
"Synchronous AJAX (Really SJAX -- Synchronous Javascript and XML) is modal which means that javascript will stop processing your program until a result has been obtained from the server. While the request is processing, the browser is effectively frozen. The browser treats the call like an alert box or a prompt box only it doesn't wait for input from the user, but on input by the remote server"
Once the browser runs the sync request, it will wait until it will get a response.
First of all, synchronous AJAX calls are evil because they are blocking the whole JavaScript browser engine (which you are aware of).
Is simply doing the call asynchronously and discarding the result if it arrives later than after a second is not enough? If you really want to wait for the result you can still use setTimeout() (jQuery for convenience, not required):
var result;
var xhr = $.ajax('/url', function(response) {
result = response;
});
setTimeout(function() {
if(result) {
//AJAX call done within a second, proceed with rendering
} else {
//One second passed, no result yet, discard it and move on
xhr.abort();
}
}, 1000);
With this approach you are not blocking the browser while still you don't have to wait for the AJAX call.
XMLHttpRequest support abort method, you can get more details about it here: http://www.w3.org/TR/XMLHttpRequest/#the-abort-method
But you need to check how many browserы support it. For example, abort was introduced in Windows Internet Explorer 7 and above.
Before or after calling send() method of XMLHttpRequest object you can setup a timer for n-seconds delay which will interrupt an asynchronous operation which is in progress.
It is possible in IE.Use the timeout property.
the code below worked for me
xmlhttp.open("method","url",false);
xmlhttp.timeout="time in ms";
xmlhttp.ontimeout=function(){};
xmlhttp.send();