Can synchronous part of async method be interupter by another thread - javascript

I'm creating an Action handler in NgXS (state management using NgRx under the hood).
Assuming that the action will be dispatched multiple times in short time period - is there a chance that more than one execution will reach doAsyncStuff() method before the first one finishes it? To be more specific - can the execution of the code be interrupted between 3rd and 4th line by another execution, so both threads will pass the 'if' check? getState and setState methods are synchronous.
#Action(ExampleAction)
public async handleAction(ctx: StateContext<StateModel>) {
if (ctx.getState().state !== 'loading') {
ctx.setState(produce(ctx.getState(), (model: StateModel) => {model.state = 'loading';}));
try {
await doAsyncStuff();
model.state = 'success';
} catch (e) {
model.state = 'error';
}
}
}
I've read some answers regarding multiple threads in JS and some of them suggest that synchronous part will never be interupted in JS, but I also fount this:
How to synchronize access to private members of a javascript object
"First, ECMAScript doesn't require JS to be executed in a single thread. Second, setTimeout() etc. are specified by HTML5 where it is clearly defined that the handler can indeed run in a parallel thread: html.spec.whatwg.org/multipage/infrastructure.html#in-parallel"
I'd like to know if it's possible that the execution of the code be interrupted between 3rd and 4th line and if it is a real possibility with most common browsers.

Related

Async/Await control flow in JavaScript/TypeScript in Node.js

Context: I'm trying to implement a rudimentary socket pool in TypeScript. My current implementation is just a list of sockets that have an "AVAILABLE/OCCUPIED" enum attached to them (it could be a boolean admittedly) that allows me to have a mutex-like mechanism to ensure each socket only sends/receives a single message at once.
What I understand: I got that Node.js's way of handling "parallel" operations is "single-threaded asynchrony".
What I infer: to me, this means that there is only a single "control pointer"/"code read-head"/"control flow position" at once, since there is a single thread. It seems to me that the readhead only ever jumps to somewhere else in the code when "await" is called, and the Promise I am "awaiting" cannot yet be resolved. But I am not sure that this is indeed the case.
What I am wondering: does "single-threaded asynchrony" ensure that there is indeed no jump of the control flow position at any other time than when "await" is called ? Or is there some underlying scheduler that may indeed cause jumps between tasks at random moments, like normal multithreading ?
My question: All of this to ask, do I need a pure mutex/compare-and-swap mechanism to ensure that my mutex-like AVAILABLE/OCCUPIED field is set appropriately ?
Consider the following code:
export enum TaskSocketStatus
{
AVAILABLE, //Alive and available
OCCUPIED, //Alive and running a task
}
export interface TaskSocket
{
status:TaskSocketStatus;
socket:CustomSocket;
}
export class Server //A gateway that acts like a client manager for an app needing to connect to another secure server
{
private sockets:TaskSocket[];
[...]
private async Borrow_Socket():Promise<TaskSocket|null>
{
for (const socket of this.sockets)
{
if (!socket.socket.Is_Connected())
{
await this.Socket_Close(socket);
continue;
}
if (socket.status === TaskSocketStatus.AVAILABLE)
{
//This line is where things could go wrong if the control flow jumped to another task;
//ie, where I'd need a mutex or compare-and-swap before setting the status
socket.status = TaskSocketStatus.OCCUPIED;
return (socket);
}
}
if (this.sockets.length < this.max_sockets)
{
const maybe_socket = await this.Socket_Create();
if (maybe_socket.isError())
{
return null;
}
//Probably here as well
maybe_socket.value.status = TaskSocketStatus.OCCUPIED;
return maybe_socket.value;
}
return null;
}
[...]
}
The issue I'm looking to avoid is two different "SendMessage" tasks borrowing the same socket because of race conditions. Maybe this is needless worry, but I'd like to make sure, as this is a potential issue that I would really prefer not to have to confront when the server is already in production...
Thanks for your help !
So, the control flow to another operation is not when await is called. It's when the running piece of Javascript returns back to the event loop and the event loop can then service the next waiting event. Resolved promises work via the event loop too (a special queue, but still in the event loop).
So, when you hit await, that doesn't immediately jump control somewhere else. It suspends further execution of that function and then causes the function to immediately return a promise and control continues with a promise being returned to the caller of the function. The caller's code continues to execute after receiving that promise. Only when the caller or the caller of the caller or the caller of the caller of the caller (depending upon how deep the call stack is) returns back to the event loop from whatever event started this whole chain of execution does the event loop get a chance to serve the next event and start a new chain of execution.
Some time later when the underlying asynchronous operation connected to that original await finishes it will insert an event into the event queue. When other Javascript execution returns control back to the event loop and this event gets to the start of the event queue, it will get executed and will resolve the promise that the await was waiting for. Only then does the code within the function after the await get a chance to run. When that async function that contained the await finally finishes it's internal execution, then the promise that was originally returned from the async function when that first await was hit will resolve and the caller will be notified that the promise it got back has been resolved (assuming it used either await or .then() on that promise).
So, there's no jumping of flow from one place to another. The current thread of Javascript execution returns control back to the event loop (by returning and unwinding its call stack) and the event loop can then serves the next waiting event and start a new chain of execution. Only when that chain of execution finishes and returns can the event loop go get the next event and start another chain of execution. In this way, there's just the one call stack frame going at a time.
In your code, I don't quite follow what you're concerned about. There is no pre-emptive switching in Javascript. If your function does an await, then its execution will be suspended at that point and other code can run before the promise gets resolved and it continues execution after the await. But, there's no pre-emptive switching that could change the context and run other code in this thread without your code calling some asynchronous operation and then continuing in the complete callback or after the await.
So, from a pure Javascript point of view, there's no worry between pure local Javascript statements that don't involve asynchronous operations. Those are guaranteed to be sequential and uninterrupted (we're assuming there's none of your code involved that uses shared memory and worker threads - which there is no sign of in the code you posted).
What I am wondering: does "single-threaded asynchrony" ensure that there is indeed no jump of the control flow position at any other time than when "await" is called ?
It ensures that there is no jump of the control flow position at any time except when you return back the event loop (unwind the call stack). It does not occur at await. await may lead to your function returning and may lead to the caller then returning back to the event loop while it waits for the returned promise to resolve, but it's important to understand that the control flow change only happens when the stack unwinds and returns control back to the event loop so the next event can be pulled from the event queue and processed.
Or is there some underlying scheduler that may indeed cause jumps between tasks at random moments, like normal multithreading ?
Assuming we're not talking about Worker Threads, there is no pre-emptive Javascript thread switching in nodejs. Execution to another piece of Javascript changes only when the current thread of Javascript returns back to the event loop.
My question: All of this to ask, do I need a pure mutex/compare-and-swap mechanism to ensure that my mutex-like AVAILABLE/OCCUPIED field is set appropriately ?
No, you do not need a mutex for that. There is no return back to the event loop between the test and set so they are guaranteed to be not interrupted by any other code.

Is it impossible to create a reliable async singleton pattern in JavaScript?

This is the function that I have:
let counter = 0;
let dbConnected = false;
async function notASingleton(params) {
if (!dbConnected) {
await new Promise(resolve => {
if (Math.random() > 0.75) throw new Error();
setTimeout((params) => {
dbConnected = true; // assume we use params to connect to DB
resolve();
}, 1000);
});
return counter++
}
};
// in another module that imports notASingleton
Promise.all([notASingleton(params), notASingleton(params), notASingleton(params), notASingleton(params)]);
or
// in another module that imports notASingleton
notASingleton(params);
notASingleton(params);
notASingleton(params);
notASingleton(params);
The problem is that apparently the notASinglton promises in might be executed concurrently and assuming they are run in parallel, the execution context for all of them will be dbConnected = false.
Note: I'm aware that we could introduce a new variable e.g. initiatingDbConnection and instead of checking for !dbConnected check for !initiatingDbConnection; however, as long as concurrently means that the context of the promises will be the same inside Promise.all, that will not change anything.
The pattern can be properly implemented in e.g. Java by utilizing the contracts of JVM for creating a class: https://stackoverflow.com/a/16106598/12144949
However, even that Java implementation cannot be used for my use case where I need to pass a variable: "The client application can’t pass any argument, so we can’t reuse it. For example, having a generic singleton class for database connection where client application supplies database server properties."
https://www.journaldev.com/171/thread-safety-in-java-singleton-classes-with-example-code
Note 2: Another possibly related issue: https://eslint.org/docs/rules/require-atomic-updates#rule-details
"On some computers, they may be executed in parallel, or in some sense concurrently, while on others they may be executed serially."
That MDN description is rubbish. I'll remove it. Promise.all is not responsible for executing anything, and promises cannot be "executed" anyway. All it does is to wait for its arguments, and you're the one who are creating those promises in the array. They would run (and concurrently open multiple connections) even if you omitted Promise.all and simply called notASingleton() multiple times.
the execution context for all of them will be dbConnected = false
Yes, but only because your dbConnected = true; is in a timeout and you are calling notASingleton() again before that happens. Not because Promise.all does anything special.

Is async recursion will be safe in Js code for polling fn

As I have heard, and actually know recursion is far not better solution for many cases if talk about sync code. But i would like to ask someone who more experienced than I am about the solution. What do you think about this code? It will work okay (as I suppose now - cause it is not syncronous) or may be it has some significant (or not so) drawbacks? Where? Why?
Guys, I would very appreciate your help, I'm doubtfull about this part of code.
Maybe there is a better solution for this?
I just want to have function which will be able to run promise function (class method) every exact time span + time for resolving this async functon.
If still enough clear.. Step by step it should -
exec target promise fn ->
waiting for resolve ->
waiting for interval ->
exec target promise fn.
And additionally it should stop if promise fn failed
Thanks in advance!
export function poll(fn: Function, every: number): number {
let pollId = 0;
const pollRecursive = async () => {
try {
await fn();
} catch (e) {
console.error('Polling was interrupted due to the error', e);
return;
}
pollId = window.setTimeout(() => {
pollRecursive();
}, every);
};
pollRecursive();
return pollId;
}
Although you have a call to pollRecursive within the function definition, what you actually do is pass a new anonymous function that will call pollRecursive when triggered by setTimeout.
The timeout sets when to queue the call to pollRecursive, but depending on the contents of that queue, the actually function will be run slightly later. In any case, it allows all other items in the queue to process in turn, unlike a tight loop / tight recursive calls, which would block the main thread.
The one addition you may want to add is more graceful error handling, as transient faults are common on the Internet (i.e. there are a lot of places where something can go missing, which makes regular failed request part of "normal business" for a TypeScript app that polls).
In your catch block, you could still re-attempt the call after the next timer, rather than stop processing. This would handle transient faults.
To avoid overloading the server after a fault, you can back off exponentially (i.e. double the every value for each contiguous fault). This reduces server load, while still enabling your application to come back online later.
If you are running at scale, you should also add jitter to this back off, otherwise the server will be flooded 2, 4, 8, 16, 32... seconds after a minor fault. This is called a stampede. By adding a little random jitter, the clients don't all come back at once.

Using "await" inside non-async function

I have an async function that runs by a setInterval somewhere in my code. This function updates some cache in regular intervals.
I also have a different, synchronous function which needs to retrieve values - preferably from the cache, yet if it's a cache-miss, then from the data origins
(I realize making IO operations in a synchronous manner is ill-advised, but lets assume this is required in this case).
My problem is I'd like the synchronous function to be able to wait for a value from the async one, but it's not possible to use the await keyword inside a non-async function:
function syncFunc(key) {
if (!(key in cache)) {
await updateCacheForKey([key]);
}
}
async function updateCacheForKey(keys) {
// updates cache for given keys
...
}
Now, this can be easily circumvented by extracting the logic inside updateCacheForKey into a new synchronous function, and calling this new function from both existing functions.
My question is why absolutely prevent this use case in the first place? My only guess is that it has to do with "idiot-proofing", since in most cases, waiting on an async function from a synchronous one is wrong. But am I wrong to think it has its valid use cases at times?
(I think this is possible in C# as well by using Task.Wait, though I might be confusing things here).
My problem is I'd like the synchronous function to be able to wait for a value from the async one...
They can't, because:
JavaScript works on the basis of a "job queue" processed by a thread, where jobs have run-to-completion semantics, and
JavaScript doesn't really have asynchronous functions — even async functions are, under the covers, synchronous functions that return promises (details below)
The job queue (event loop) is conceptually quite simple: When something needs to be done (the initial execution of a script, an event handler callback, etc.), that work is put in the job queue. The thread servicing that job queue picks up the next pending job, runs it to completion, and then goes back for the next one. (It's more complicated than that, of course, but that's sufficient for our purposes.) So when a function gets called, it's called as part of the processing of a job, and jobs are always processed to completion before the next job can run.
Running to completion means that if the job called a function, that function has to return before the job is done. Jobs don't get suspended in the middle while the thread runs off to do something else. This makes code dramatically simpler to write correctly and reason about than if jobs could get suspended in the middle while something else happens. (Again it's more complicated than that, but again that's sufficient for our purposes here.)
So far so good. What's this about not really having asynchronous functions?!
Although we talk about "synchronous" vs. "asynchronous" functions, and even have an async keyword we can apply to functions, a function call is always synchronous in JavaScript. An async function is a function that synchronously returns a promise that the function's logic fulfills or rejects later, queuing callbacks the environment will call later.
Let's assume updateCacheForKey looks something like this:
async function updateCacheForKey(key) {
const value = await fetch(/*...*/);
cache[key] = value;
return value;
}
What that's really doing, under the covers, is (very roughly, not literally) this:
function updateCacheForKey(key) {
return fetch(/*...*/).then(result => {
const value = result;
cache[key] = value;
return value;
});
}
(I go into more detail on this in Chapter 9 of my recent book, JavaScript: The New Toys.)
It asks the browser to start the process of fetching the data, and registers a callback with it (via then) for the browser to call when the data comes back, and then it exits, returning the promise from then. The data isn't fetched yet, but updateCacheForKey is done. It has returned. It did its work synchronously.
Later, when the fetch completes, the browser queues a job to call that promise callback; when that job is picked up from the queue, the callback gets called, and its return value is used to resolve the promise then returned.
My question is why absolutely prevent this use case in the first place?
Let's see what that would look like:
The thread picks up a job and that job involves calling syncFunc, which calls updateCacheForKey. updateCacheForKey asks the browser to fetch the resource and returns its promise. Through the magic of this non-async await, we synchronously wait for that promise to be resolved, holding up the job.
At some point, the browser's network code finishes retrieving the resource and queues a job to call the promise callback we registered in updateCacheForKey.
Nothing happens, ever again. :-)
...because jobs have run-to-completion semantics, and the thread isn't allowed to pick up the next job until it completes the previous one. The thread isn't allowed to suspend the job that called syncFunc in the middle so it can go process the job that would resolve the promise.
That seems arbitrary, but again, the reason for it is that it makes it dramatically easier to write correct code and reason about what the code is doing.
But it does mean that a "synchronous" function can't wait for an "asynchronous" function to complete.
There's a lot of hand-waving of details and such above. If you want to get into the nitty-gritty of it, you can delve into the spec. Pack lots of provisions and warm clothes, you'll be some time. :-)
Jobs and Job Queues
Execution Contexts
Realms and Agents
You can call an async function from within a non-async function via an Immediately Invoked Function Expression (IIFE):
(async () => await updateCacheForKey([key]))();
And as applied to your example:
function syncFunc(key) {
if (!(key in cache)) {
(async () => await updateCacheForKey([key]))();
}
}
async function updateCacheForKey(keys) {
// updates cache for given keys
...
}
This shows how a function can be both sync and async, and how the Immediately Invoked Function Expression idiom is only immediate if the path through the function being called does synchronous things.
function test() {
console.log('Test before');
(async () => await print(0.3))();
console.log('Test between');
(async () => await print(0.7))();
console.log('Test after');
}
async function print(v) {
if(v<0.5)await sleep(5000);
else console.log('No sleep')
console.log(`Printing ${v}`);
}
function sleep(ms : number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
test();
(Based off of Ayyappa's code in a comment to another answer.)
The console.log looks like this:
16:53:00.804 Test before
16:53:00.804 Test between
16:53:00.804 No sleep
16:53:00.805 Printing 0.7
16:53:00.805 Test after
16:53:05.805 Printing 0.3
If you change the 0.7 to 0.4 everything runs async:
17:05:14.185 Test before
17:05:14.186 Test between
17:05:14.186 Test after
17:05:19.186 Printing 0.3
17:05:19.187 Printing 0.4
And if you change both numbers to be over 0.5, everything runs sync, and no promises get created at all:
17:06:56.504 Test before
17:06:56.504 No sleep
17:06:56.505 Printing 0.6
17:06:56.505 Test between
17:06:56.505 No sleep
17:06:56.505 Printing 0.7
17:06:56.505 Test after
This does suggest an answer to the original question, though. You could have a function like this (disclaimer: untested nodeJS code):
const cache = {}
async getData(key, forceSync){
if(cache.hasOwnProperty(key))return cache[key] //Runs sync
if(forceSync){ //Runs sync
const value = fs.readFileSync(`${key}.txt`)
cache[key] = value
return value
}
//If we reach here, the code will run async
const value = await fsPromises.readFile(`${key}.txt`)
cache[key] = value
return value
}
Now, this can be easily circumvented by extracting the logic inside updateCacheForKey into a new synchronous function, and calling this new function from both existing functions.
T.J. Crowder explains the semantics of async functions in JavaScript perfectly. But in my opinion the paragraph above deserves more discussion. Depending on what updateCacheForKey does, it may not be possible to extract its logic into a synchronous function because, in JavaScript, some things can only be done asynchronously. For example there is no way to perform a network request and wait for its response synchronously. If updateCacheForKey relies on a server response, it can't be turned into a synchronous function.
It was true even before the advent of asynchronous functions and promises: XMLHttpRequest, for instance, gets a callback and calls it when the response is ready. There's no way of obtaining a response synchronously. Promises are just an abstraction layer on callbacks and asynchronous functions are just an abstraction layer on promises.
Now this could have been done differently. And it is in some environments:
In PHP, pretty much everything is synchronous. You send a request with curl and your script blocks until it gets a response.
Node.js has synchronous versions of its file system calls (readFileSync, writeFileSync etc.) which block until the operation completes.
Even plain old browser JavaScript has alert and friends (confirm, prompt) which block until the user dismisses the modal dialog.
This demonstrates that the designers of the JavaScript language could have opted for synchronous versions of XMLHttpRequest, fetch etc. Why didn't they?
[W]hy absolutely prevent this use case in the first place?
This is a design decision.
alert, for instance, prevents the user from interacting with the rest of the page because JavaScript is single threaded and the one and only thread of execution is blocked until the alert call completes. Therefore there's no way to execute event handlers, which means no way to become interactive. If there was a syncFetch function, it would block the user from doing anything until the network request completes, which can potentially take minutes, even hours or days.
This is clearly against the nature of the interactive environment we call the "web". alert was a mistake in retrospect and it should not be used except under very few circumstances.
The only alternative would be to allow multithreading in JavaScript which is notoriously difficult to write correct programs with. Are you having trouble wrapping your head around asynchronous functions? Try semaphores!
It is possible to add a good old .then() to the async function and it will work.
Should consider though instead of doing that, changing your current regular function to async one, and all the way up the call stack until returned promise is not needed, i.e. there's no work to be done with the value returned from async function. In which case it actually CAN be called from a synchronous one.

Why couldn't popular JavaScript runtimes handle synchronous-looking asynchronous script?

As cowboy says down in the comments here, we all want to "write [non-blocking JavaScript] asynchronous code in a style similar to this:
try
{
var foo = getSomething(); // async call that would normally block
var bar = doSomething(foo);
console.log(bar);
}
catch (error)
{
console.error(error);
}
"
So people have come up solutions to this problem like
callback libraries (eg async)
promises
event patterns
streamline
domains and
generators.
But none of these lead to code as simple and easy to understand as the sync-style code above.
So why isn't possible for javascript compilers/interpreters to just NOT block on the statements we currently know as "blocking"? So why isn't possible for javascript compilers/interpreters to handle the sync syntax above AS IF we'd written it in an async style?"
For example, upon processing getSomething() above, the compiler/interpreter could just say "this statement is a call to [file system/network resource/...], so I'll make a note to listen to responses from that call and in the meantime get on with whatever's in my event loop". When the call returns, execution can proceed to doSomething().
You would still maintain all of the basic features of popular JavaScript runtime environments
single threaded
event loop
blocking operations (I/O, network, wait timers) handled "asynchronously"
This would be simply a tweak to the syntax, that would allow the interpreter to pause execution on any given bit of code whenever IT DETECTS an async operation, and instead of needing callbacks, code just continues from the line after the async call when the call returns.
As Jeremy says
there is nothing in the JavaScript runtime that will preemptively
pause the execution of a given task, permit some other code to execute
for a while, and then resume the original task
Why not? (As in, "why couldn't there be?"... I'm not interested in a history lesson)
Why does a developer have to care about whether a statement is blocking or not? Computers are for automating stuff that humans are bad at (eg writing non-blocking code).
You could perhaps implement it with
a statement like "use noblock"; (a bit like "use strict";) to turn this "mode" on for a whole page of code. EDIT: "use noblock"; was a bad choice, and misled some answerers that I was trying to change the nature of common JavaScript runtimes altogether. Something like 'use syncsyntax'; might better describe it.
some kind of parallel(fn, fn, ...); statement allowing you to run things in parallel while in "use syncsyntax"; mode - eg to allow multiple async activities to be kicked off at once
EDIT: a simple sync-style syntax wait(), which would be used instead of setTimeout() in "use syncsyntax"; mode
EDIT:
As an example, instead of writing (standard callback version)
function fnInsertDB(myString, fnNextTask) {
fnDAL('insert into tbl (field) values (' + myString + ');', function(recordID) {
fnNextTask(recordID);
});
}
fnInsertDB('stuff', fnDeleteDB);
You could write
'use syncsyntax';
function fnInsertDB(myString) {
return fnDAL('insert into tbl (field) values (' + myString ');'); // returns recordID
}
var recordID = fnInsertDB('stuff');
fnDeleteDB(recordID);
The syncsyntax version would process exactly the same way as the standard version, but it's much easier to understand what the programmer intended (as long as you understand that syncsyntax pauses execution on this code as discussed).
So why isn't possible for javascript compilers/interpreters to just NOT block on the statements we currently know as "blocking"?
Because of concurrency control. We want them to block, so that (in JavaScript's single-threaded nature) we are safe from race conditions that alter the state of our function while we still are executing it. We must not have an interpreter that suspends the execution of the current function at any arbitrary statement/expression and resumes with some different part of the program.
Example:
function Bank() {
this.savings = 0;
}
Bank.prototype.transfer = function(howMuch) {
var savings = this.savings;
this.savings = savings + +howMuch(); // we expect `howMuch()` to be blocking
}
Synchronous code:
var bank = new Bank();
setTimeout(function() {
bank.transfer(prompt); // Enter 5
alert(bank.savings); // 5
}, 0);
setTimeout(function() {
bank.transfer(prompt); // Enter 3
alert(bank.savings); // 8
}, 100);
Asynchronous, arbitrarily non-blocking code:
function guiPrompt() {
"use noblock";
// open form
// wait for user input
// close form
return input;
}
var bank = new Bank();
setTimeout(function() {
bank.transfer(guiPrompt); // Enter 5
alert(bank.savings); // 5
}, 0);
setTimeout(function() {
bank.transfer(guiPrompt); // Enter 3
alert(bank.savings); // 3 // WTF?!
}, 100);
See https://glyph.twistedmatrix.com/2014/02/unyielding.html for a longer (and language-agnostic) explanation.
there is nothing in the JavaScript runtime that will preemptively pause the execution of a given task, permit some other code to execute for a while, and then resume the original task
Why not?
For simplicity and security, see above. (And, for the history lesson: That's how it just was done)
However, this is no longer true. With ES6 generators, there is something that lets you explicitly pause execution of the current function generator: the yield keyword.
As the language evolves, there are also async and await keywords planned for ES7.
generators [… don't …] lead to code as simple and easy to understand as the sync code above.
But they do! It's even right in that article:
suspend(function* () {
// ^ "use noblock" - this "function" doesn't run continuously
try {
var foo = yield getSomething();
// ^^^^^ async call that does not block the thread
var bar = doSomething(foo);
console.log(bar);
} catch (error) {
console.error(error);
}
})
There is also a very good article on this subject here: http://howtonode.org/generators-vs-fibers
Why not? No reason, it just hadn't been done.
And here in 2017, it has been done in ES2017: async functions can use await to wait, non-blocking, for the result of a promise. You can write your code like this if getSomething returns a promise (note the await) and if this is inside an async function:
try
{
var foo = await getSomething();
var bar = doSomething(foo);
console.log(bar);
}
catch (error)
{
console.error(error);
}
(I've assumed there that you only intended getSomething to be asynchronous, but they both could be.)
Live Example (requires up-to-date browser like recent Chrome):
function getSomething() {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.5) {
reject(new Error("failed"));
} else {
resolve(Math.floor(Math.random() * 100));
}
}, 200);
});
}
function doSomething(x) {
return x * 2;
}
(async () => {
try
{
var foo = await getSomething();
console.log("foo:", foo);
var bar = doSomething(foo);
console.log("bar:", bar);
}
catch (error)
{
console.error(error);
}
})();
The first promise fails half the time, so click Run repeatedly to see both failure and success.
You've tagged your question with NodeJS. If you wrap the Node API in promises (for instance, with promisify), you can write nice straight-forward synchronous-looking code that runs asynchronously.
Because Javascript interpreters are single-threaded, event driven. This is how the initial language was developed.
You can't do "use noblock" because no other work can occur during that phase. This means your UI will not update. You cannot respond to mouse or other input event from the user. You cannot redraw the screen. Nothing.
So you want to know why? Because javascript can cause the display to change. If you were able to do both simultaneously you'd have all these horrible race conditions with your code and the display. You might think you've moved something on the screen, but it hasn't drawn, or it drew and you moved it after it drew and now it's gotta draw again, etc. This asynchronous nature allows, for any given event in the execution stack to have a known good state -- nothing is going to modify the data that is being used while this is being executed.
That is not to say what you want doesn't exist, in some form.
The async library allows you to do things like your parallel idea (amongst others).
Generators/async/wait will allow you to write code that LOOKS like what you want (although it'll be asynchronous by nature).
Although you are making a false claim here -- humans are NOT bad at writing asynchronous code.
The other answers talked about the problems multi-threading and parallelism introduce. However, I want to address your answer directly.
Why not? (As in, "why couldn't there be?"... I'm not interested in a history lesson)
Absolutely no reason. ECMAScript - the JavaScript specification says nothing about concurrency, it does not specify the order code runs in, it does not specify an event loop or events at all and it does not specify anything about blocking or not blocking.
The way concurrency works in JavaScript is defined by its host environment - in the browser for example that's the DOM and the DOM specifies the semantics of the event loop. "async" functions like setTimeout are only the concern of the DOM and not the JavaScript language.
Moreover there is nothing that says JavaScript runtimes have to run single threaded and so on. If you have sequential code the order of execution is specified, but there is nothing stopping anyone from embedding the JavaScript language in a multi threaded environment.

Categories

Resources