Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
228 views
in Technique[技术] by (71.8m points)

node.js - 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

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...