Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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).

like image 993
poshest Avatar asked Aug 22 '14 11:08

poshest


People also ask

Does JavaScript run synchronous or asynchronous?

JavaScript is a single-threaded, non-blocking, asynchronous, concurrent programming language with lots of flexibility.

Why is JavaScript not synchronous?

Well, Javascript is Synchronous, It is a synchronous, single-threaded language. Because it has a single thread that's why it can only execute one command at a time and the other commands need to wait for executing before the running command executes. And the term synchronous means one at a time.

Why is JavaScript not asynchronous?

JavaScript is only asynchronous in the sense that it can make, for example, Ajax calls. The Ajax call will stop executing and other code will be able to execute until the call returns (successfully or otherwise), at which point the callback will run synchronously. No other code will be running at this point.

How asynchronous events are handled in JavaScript?

An async function can contain an await expression, that pauses the execution of the function and waits for the passed Promise's resolution, and then resumes the async function's execution and returns the resolved value. You can think of a Promise in JavaScript as the equivalent of Java's Future or C# 's Task.


1 Answers

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);

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

like image 122
Bergi Avatar answered Oct 05 '22 02:10

Bergi