asynchronous code such as setTimeout can only be run by using a browser; as the engine hands over the code to the browser till the time of execution comes. But in node, we have only an engine and no browser then how does setTimeout work on the node.
Asynchronous code is achieved using Promises, and optionally the async/await syntactic sugar.
Promises are implemented using raw JavaScript, and has nothing to do with whether the code is ran in the browser or not.
In your case you are referring to setTimeout. This function simply delays code execution by scheduling for the function to be called in JavaScript's event loop.
This is part of the core engine of JavaScript, and once again has nothing to do with the browser.
What makes you think that the browser makes any difference here?
Any implementation will have a mechanism in place for being able to wait for a certain amount of time to pass, this is not something special to a browser.
Related
I have a NodeJS/Express web app, where TypeOrm is used for many database functions. To avoid callback hell I usually use async/await to call and wait for database actions from my endpoint methods.
I've heard, however, that methods like fs.readFileSync should always be avoided, since they are blocking and will force all other requests to wait. Does this also apply to async/await? Do I have to use promises and callbacks to get decent multi-user performance?
Sync functions really BLOCK the event loop, until the io is complete. But in other hand async-await is just syntactic sugar to the Promise chaining. It is not actually synchronous, it just looks like it. That is the biggest difference you need to understand.
But, Some problems are introduces with async-await making the promises too sequential.
For example, two independent promises should be executed parallelly with Promise.all But when you use async-await you tend to do
await func1();
await func2();
So, logically you may make bottleneck yourself. But syntactically it has no problems like Sync ones whatsoever.
You can check out ES5 transpilation using Babel REPL, you may understand a little bit better.
The reason you shouldn't use *Sync functions is that they block the event loop. That causes your application to become irresponsive while synchronous functions are being executed.
Promises help you avoid the callback hell problem when you are dealing with async code. Additionally, async/await syntax allows you to write asynchronous code that LOOKS like synchronous code. So it's perfectly fine to use async and await.
I've heard, however, that methods like fs.readFileSync should always be avoided, since they are blocking and will force all other requests to wait.
This is true, mostly.
Remember that your server doesn't run on a single pipeline. Rather, you use the cluster API to run multiple worker processes side-by-side (where the number of cores of the server's CPU limits the number of worker processes that should be run).
In reality then, even if a single event loop is blocked by a synchronous IO and other requests that are assigned to the very same loop are forced to wait, other worker processes are still able to process incoming requests.
On the other hand, if you make a request await an IO operation, the loop is able to pick up another request and process it. But, there's a trade off.
Suppose first request comes, you await a fs.readFile. The second request comes and it's processed. But the second request doesn't wait for any IO, rather, it's a CPU-bound operation (a heavy calculation maybe?). The IO operation triggered by the first request completes but it has to wait until the second request completes and only then the continuation can be picked up by the event loop and the response can be sent back.
Do I have to use promises and callbacks to get decent multi-user performance?
A simple answer would be yes, however, be careful and monitor your app to not to fall in a pitfall (e.g. mixing IO requests with CPU intensive tasks where the performance of async IO could be worse from the client's perspective).
Using async/await in Node.js syntax is preferable to the alternatives, which are stock promises or especially callbacks. It allows for much cleaner code which is easier to understand and maintain. We used to have to use babel to transpile to access these in older times but they've been in Node for ages now so I'd recommend for people to use them.
I used to consider async as equavelent as multithreading. Multi tasks will be done parallel. However, in javascript I wrote this and it seems that dosomething will never happen.
setTimeout(1000, dosomething)
while(true){}
Why?
Node.js is a single threaded asynchronous language. As mentioned in another answer
Javascript is single threaded (with the exception of web workers, but that is irrelavent to this example so we will ignore it). What this means is that setTimeout actually does is schedules some code to be executed some time in the future, after at least some amount of time, but only when the browser has stopped whatever else it was doing on the rendering thread at the time, which could be rendering html, or executing javascript.
In your example the execution of the while loop never stops, control is never returned to the top level, so the scheduled setTimeout function is never executed.
Multithreading is one of many ways to implement asynchronous programming. Reacting to events and yielding to a scheduler is one other way, and happens to be the way that javascript in the browser is implemented.
In your example, the event that gave you control and allowed you to call setTimeout must be allowed to complete so that the javascript engine can monitor the timeout and call your doSomething callback when it expires.
I'm trying to connect to a 3rd party library, that has a function that can block. I would like to use it, but without blocking. Is it possible to wrap a blocking call that I don't have the control of, to make it async?
// calling this function will block the nodejs thread
blockingCall();
What I would like would be something like this.
// wrapper for the blocking call
var wrapper = wrapBlockingCall(blockingCall);
wrapper.on('complete', function() {});
Is this possible? Does this make sense?
There is no way to make a blocking JavaScript code non-blocking in Node.js - the mechanism which Node uses for its non-blocking behaviour is implemented in the C/C++ layer, which in turn is used only when doing I/O operations (reading from disk, networking etc.).
In reality, every line of JavaScript your program uses will be executed one-by-one, because it is always executed on the same thread, no matter what you do.
The only option I see is to execute the offending code in a separate Node process using the built-in Child Process module. However, this will have significant performance impact, even bigger one if the code needs to be executed frequently.
Note:
After reading the comments under your question, it seems that you are actually the author of the blocking function, which in turn calls a C API which performs blocking I/O. There are ways of calling C functions which would normally block in a manner which does not block the upper JavaScript layer.
While I am not a C expert, I think this is accomplished using the libuv library included in Node - have a look at the addons documentation for more info.
I'm quite sure with this, but just to have your opinion:
Is it somehow possible to perform operations in the background with Javascript if web workers are not available?
Is there perhaps a way to "misuse" the asynchronous setTimeout() function or some other mechanisms?
My goal is to read things from the localStorage, do a few transformations and send them via Ajax.
Thanks.
You can't run operation in background, but you can split it in small chunks, and run each next part with setTimeout. As result browser will have time to render changes and will be responsive to normal actions, while your long process will be executed as well
function iteration(){
do_some_small_amount_of_work();
if (!not_finished)
scheduler.setTimeout(iteration, 1);
}
There is not really multithreading in Javascript, but you can run code asynchronously using setTimeout(code, 0). This queues the function for execution.
Without using web workers, what you've suggested (using setTimeout) is the only way to do it, and of course it's not really "background" at all at that point. Note that you'll need to keep the processing quite short each time you fire the "background" code, because it's not really background code at all; while your code is running, the page will be fairly unresponsive (the degree to which it's unresponsive will vary by browser, but certainly any JavaScript code on the page will have to wait for your function call to finish).
No, there is no way to do anything in the background in Javascript. It's strictly single threaded.
You can use setTimeout or setInterval to do the work in the foreground, but just a small part of it each time. That way the interface is still reasonably responsive as it handles events between your bursts of work.
So, after reading a little about non-blocking code, does...
response.write(thisWillTakeALongTime());
...block the process? If so, do we need to pass the response into pretty much every slow function call we make, and have that function handle the response?
Thanks for helping to clarify!
Yes, it will block the event loop. And passing the response object into the slow function won't help, no matter where you call the slow function you will be blocking the event loop.
As to how to fix it, we will need more information.
What is making your slow function slow? Are you performing large calculations?
Are you doing sync versions of file/database calls?
It depends on what you mean by process. The web server has already finished serving the page at this point you js will execute however the request is synchronous so the javascript will continue to devote its in your function until it returns regardless even if take years. (hopefully by this point the browser will detect your script is taking too long and give you the opportunity to kill it). Even still you suffer the embarrassment of the user having to kill your javascript functionality and them not being able to use the page.
So how do you solve the problem. The time when this gets particular important is when your js is making the problem because at the point a whole host of things of things can go wrong. Imagine that your user is on the other side of the earth. the network latency could make your js painfully slow. when using ajax its preferable to use Asynchronous requests which get around this. I personally recommend using jquery as it makes async ajax calls really easy and the documentation on the side is quite straight forward. The other thing I recommend is making the return output small. It made be better to return json output and build the needed html from that.