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

前端 未结 4 626
鱼传尺愫
鱼传尺愫 2020-11-28 15:39

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         


        
4条回答
  •  佛祖请我去吃肉
    2020-11-28 16:05

    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

提交回复
热议问题