JavaScript: Does an async function create a new thread? - javascript

Mozilla’s documentation on XMLHttpRequest includes the following on the async parameter:
Note: Synchronous requests on the main thread can be easily disruptive to the user experience and should be avoided; in fact, many browsers have deprecated synchronous XHR support on the main thread entirely.
That makes sense, as you don’t what to hold up the main thread waiting for an indeterminate period of time.
If I create an async function which includes usng XMLHttpRequest, would that qualify as a new thread?
I know about fetch(), I know about promises, and I know about using XMLHttpRequest with callbacks. This question is about the async keyword.

JavaScript (in the browser) is entirely single-threaded (with the exception of WebWorkers). The term "asynchronous" doesn't necessarily have anything to do with being multi-threaded.
The network fetch likely happens on browser "networking" thread in a higher performance language (c++, rust, etc.), but this means nothing to JavaScript.
What synchronous means in JavaScript terms is that the c++ code that handles the actual network request will pause the JavaScript event loop until the request completes. That means absolutely nothing can happen in the JavaScript context until the request finishes.
Therefore async means that you can do other things on the single JavaScript thread while the network fetch happens in the background. This is facilitated by c++ calling a JavaScript callback or resolving a JavaScript Promise (aka async/await).
I will try to elaborate more clearly in pseudocode:
const response = makeRequest({ asyncMode: false });
//nothing can happen until this request finishes
//requestAnimationFrame animation code or click event listeners will not run
// until the request is finished
makeRequest({ asyncMode: true, callback: function(response, error){ console.log("this will execute later once the network request is made") } });
console.log("this code will run right away");
//requestAnimationFrame animation code or click event listeners will run as normal
// during the request

Related

migration from iOS cordova UIwebview to wkwebview disable asynchronous javascript execution to support the existing application

In one of our older ‘Save Data’ examples, we had previously used the following and it was working fine without any issues in cordova UIWebview.
var filenameID;
function getFilenameID() {
$.ajax('/jquery/getdata', // request url
{
success: function (data, status, xhr) {// success callback function
kp_requestKioskId_callback(data);
}});
}
function kp_requestKioskId_callback(kioskId) {
filenameID = kioskId.split(" ").join("");
}
function saveData(fileName, data) {
getFilenameID();
kp_FileAPI_writeToFile(filenameID + ".xls", data, "writeFile_callback");
}
After migrating from UIWebview to WKWebview, In WKWebView since JavaScript code is executed asynchronously, the ‘getFilenameID’ call is not completed before the ‘kp_FileAPI_writeToFile’ call is executed, resulting in an undefined filename.
Copying the kp_FileAPI_writeToFile function inside kp_requestKioskId_callback will solve the issue.
But we have many similar kind of functions in our application.
Is there a way to solve or disable the asynchronous javascript execution to avoid major changes on the application
Is there a way to solve or disable the asynchronous javascript execution to avoid major changes on the application
No, in modern browsers/webviews XmlHttpRequest (which is what $.ajax uses behind the scenes) disallows synchronous requests from the main thread. The flag to disable asynchronous behaviour still exists but most browsers will throw an exception if you use it inside the main thread.
You can use synchronous XmlHttpRequest inside web workers, but that isn't making your application synchronous, and you can't use Cordova plugin APIs from web workers either, so you'll find this quite limiting.
The code sample shown you aren't even using the async option, and by default the option is set to true, which means your network request running on UIWebView was also running asynchronously, thus you have is an nondeterministic race condition.
I have never encountered this issue on the UIWebview, after migrating to WKWebview javascript code behaves asynchrously.
For e.g:
We have 3 API calls which are dependent on one after the other for a single product
Consider if we have 2 products, we are iterating the products in a loop and triggering 3 API for each product.
In WKWebview, it finishes the first thread and at last 2nd flow

Does node js execute multiple commands in parallel?

Does node js execute multiple commands in parallel or execute one command (and finish it!) and then execute the second command?
For example if multiple async functions use the same Stack, and they push & pop "together", can I get strange behaviour?
Node.js runs your main Javascript (excluding manually created Worker Threads for now) as a single thread. So, it's only ever executing one piece of your Javascript at a time.
But, when a server request contains asynchronous operations, what happens in that request handle is that it starts the asynchronous operation and then returns control back to the interpreter. The asynchronous operation runs on its own (usually in native code). While all that is happening, the JS interpreter is free to go back to the event loop and pick up the next event waiting to be run. If that's another incoming request for your server, it will grab that request and start running it. When it hits an asynchronous operation and returns back to the interpreter, the interpreter then goes back to the event loop for the next event waiting to run. That could either be another incoming request or it could be one of the previous asynchronous operations that is now ready to run it's callback.
In this way, node.js makes forward progress on multiple requests at a time that involve asynchronous operations (such as networking, database requests, file system operations, etc...) while only ever running one piece of your Javascript at a time.
Starting with node v10.5, nodejs has Worker Threads. These are not automatically used by the system yet in normal service of networking requests, but you can create your own Worker Threads and run some amount of Javascript in a truly parallel thread. This probably isn't need for code that is primarily I/O bound because the asynchronous nature of I/O in Javascript already gives it plenty of parallelism. But, if you had CPU-intensive operations (heavy crypto, image analysis, video compression, etc... that was done in Javascript), Worker Threads may definitely be worth adding for those particular tasks.
To show you an example, let's look at two request handlers, one that reads a file from disk and one that fetches some data from a network endpoint.
app.get("/getFileData", (req, res) => {
fs.readFile("myFile.html", function(err, html) {
if (err) {
console.log(err);
res.sendStatus(500);
} else {
res.type('html').send(html);
}
})
});
app.get("/getNetworkData", (req, res) => {
got("http://somesite.com/somepath").then(result => {
res.json(result);
}).catch(err => {
console.log(err);
res.sendStatus(500);
});
});
In the /getFileData request, here's the sequence of events:
Client sends request for http://somesite.com/getFileData
Incoming network event is processed by the OS
When node.js gets to the event loop, it sees an event for an incoming TCP connection on the port its http server is listening for and calls a callback to process that request
The http library in node.js gets that request, parses it, and notifies the observes of that request, once of which will be the Express framework
The Express framework matches up that request with the above request handler and calls the request handler
That request handler starts to execute and calls fs.readFile("myfile.html", ...). Because that is asynchronous, calling the function just initiates the process (carrying out the first steps), registers its completion callback and then it immediately returns.
At this point, you can see from that /getFileData request handler that after it calls fs.readFile(), the request handler just returns. Until the callback is called, it has nothing else to do.
This returns control back to the nodejs event loop where nodejs can pick out the next event waiting to run and execute it.
In the /getNetworkData request, here's the sequence of events
Steps 1-5 are the same as above.
6. The request handler starts to execute and calls got("http://somesite.com/somepath"). That initiates a request to that endpoint and then immediately returns a promise. Then, the .then() and .catch() handlers are registered to monitor that promise.
7. At this point, you can see from that /getNetworkData request handler that after it calls got().then().catch(), the request handler just returns. Until the promise is resolved or rejected, it has nothing else to do.
8. This returns control back to the nodejs event loop where nodejs can pick out the next event waiting to run and execute it.
Now, sometime in the future, fs.readFile("myFile.html", ...) completes. At this point, some internal sub-system (that may use other native code threads) inserts a completion event in the node.js event loop.
When node.js gets back to the event loop, it will see that event and run the completion callback associated with the fs.readFile() operation. That will trigger the rest of the logic in that request handler to run.
Then, sometime in the future the network request from got("http://somesite.com/somepath") will complete and that will trigger an event in the event loop to call the completion callback for that network operation. That callback will resolve or reject the promise which will trigger the .then() or .catch() callbacks to be called and the second request will execute the rest of its logic.
Hopefully, you can see from these examples how request handlers initiate an asynchronous operation, then return control back to the interpreter where the interpreter can then pull the next event from the event loop and run it. Then, as asynchronous operations complete, other things are inserted into the event loop causing further progress to run on each request handler until eventually they are done with their work. So, multiple sections of code can be making progress without more than one piece of code every running at the same time. It's essentially cooperative multi-tasking where the time slicing between operations occurs at the boundaries of asynchronous operations, rather than an automatic pre-emptive time slicing in a fully threaded system.
Nodejs gets a number of advantages from this type of multi-tasking as it's a lot, lot lower overhead (cooperative task switching is a lot more efficient than time-sliced automatic task switching) and it also doesn't have most of the usual thread synchronization issues that true multi-threaded systems do which can make them a lot more complicated to code and/or more prone to difficult bugs.

Call cloud functions without waiting for response

Trying a little hack here with cloud functions but can't seem to figure out what the issue is.
I'm currently using now.sh to host serverless functions and would like to call 1 function from another. Lets say I have 2 functions declared fetchData & setData. When the setData function is called it processes some data and then calls the fetchData function.
export const setData = async (req: Request, res: Response) => {
await axios.post(
fetchDataEndpointUrl,
{
params: {
key,
},
},
);
return res.json({
payload: true,
});
}
The above code works fine but the time taken for the entire operation to complete would be setData function call + the time taken for the fetchData function call to complete. What I'm trying to do is make a call to fetchData without having to wait for it to complete essentially removing the await in the axios call. I've tried removing the await but the call just ends abruptly when the setData call ends. Is there a way to decouple this action and not have to wait for the setData function to complete?
The summary of your question appears to be that when you call a Cloud Function, you want it to be able to return a value to its caller while simultaneously performing background work such as calling another service and waiting for a response.
When you return a value to the caller for a Cloud Function, that is the end of the life span of the Cloud Function. You can not be assured of any kind of life in the Cloud Function beyond the return.
This is documented here.
The text (in part) reads:
A function has access to the resources requested (CPU and memory) only
for the duration of function execution. Code run outside of the
execution period is not guaranteed to execute, and it can be stopped
at any time. Therefore, you should always signal the end of your
function execution correctly and avoid running any code beyond it.
Another part of the question is what if we want to have our Cloud Function make an asynchronous REST call where we don't care about waiting for the response. Can we return from the Cloud Function without waiting for the nested REST call to complete?
The answer is maybe but it will depend on the nature of service being called and how we are calling it. To appreciate the nuances in this remember that JavaScript is a single threaded language. There aren't multiple threads of execution. In our JavaScript app, only one thing will ever happen at a time. If we make an asynchronous REST call and don't care about a reply but (obviously) do care that the request has been sent then we need to synchronously send the request before we terminate the Cloud Function. This can get tricky if we start using library packages without delving into their natures. For example, a REST call might include:
A socket connection to the partner
A transmission of the outbound request
A callback when the response is received
We need to be absolutely sure that the transmission has happened before we end the top level Cloud Function call. In addition, if we do end the top level Cloud Function call, that may very well tare down the socket used for the response. This could result in an exception in the called REST service that now is unable to return its 200 response.
To run work where we don't need to nor want to wait for a response, GCP provides an architected solution for this. It is called "Cloud Tasks" (see Cloud Tasks). Within your Cloud Function, you would define a request to call your nested service asynchronously and hand that request off to Cloud Tasks to execute. Cloud Tasks would acknowledge receipt of the request to execute and you can now be assured that it will and can return at the highest level.

NodeJS: client.emit('message') needs delay after connection in order to be seen

I'm using socket.io in a Node application. Here is a snippet from my code:
io.sockets.on('connection', socket => {
setTimeout(function () {
console.log('a client connected!')
clients.forEach(s => s.emit('to_client', 'a client connected'))
}, 0)
})
If I remove the setTimeout wrapper, 'a client connected' is not seen in the console of the client (Chrome browser), however, even with a timeout of zero, it does show up. What could be the issue? I would prefer going without the setTimeout since it does not sound like something that should be required here.
Node is an asynchronous single threaded run-time so it uses callbacks to avoid blocking the I/O.
Using the setTimeout is one way (along with nodes built in process.nextTick() method for handling asynchronous code!). Your example code is trying to access clients, I suspect whatever is handling this has not been initialised before your connection callback has executed.
The setTimeout method basically pushes the code (callback function) onto the event queue and therefore anything currently on the call stack will be processed before this setTimeout callback can be run.

understanding of node js performance

I recently discovered Node js and I read in various articles that Node js is fast and can handle more requests than a Java server although Node js use a single thread.
I understood that Node is based on an event loop, each call to a remote api or a database is done with an async call so the main thread is never blocked and the server can continue to handle others client requests.
If I understood well, each portion of code that can take times should be processed with an async call otherwise the server will be blocked and it won't be able to handle others requests ?
var server = http.createServer(function (request, response) {
//CALL A METHOD WHICH CAN TAKE LONG TIME TO EXECUTE
slowSyncMethod();
//THE SERVER WILL STILL BE ABLE TO HANDLER OTHERS REQUESTS ??
response.writeHead(200, {"Content-Type":"text/plain"});
response.end("");
});
So if my understanding is correct, the above code is bad because the synchronous call to the slow method will block the Node js main thread ? Is Node js fast on condition that all the code that can take times are executed in an async manner ?
NodeJs is as fast as your hardware(vm) and the v8 that is running it. that being said, any heavy duty task like any type of media(music, image, video etc) file processing will definitively lock your application. so will computation on large collections thats why the async model is leveraged though events, and deferred invocations. that being said nothing stops you from spawning child processes to relegate heavy duty and asynchronously get back the result. But if you are finding your self in the need to do this for many tasks, maybe you should revisit your architecture.
I hope thhis helps

Categories

Resources