为什么不能流行的JavaScript运行时处理同步,异步看剧本? [英] Why couldn't popular JavaScript runtimes handle synchronous-looking asynchronous script?

查看:113
本文介绍了为什么不能流行的JavaScript运行时处理同步,异步看剧本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于牛仔说,倒在这里的意见,我们都希望能够写[非阻塞的JavaScript]异步code下的风格与此类似:

 尝试
 {
    无功富= getSomething(); //异步调用,通常会阻塞
    VAR栏= DoSomething的(富);
    的console.log(巴);
 }
 赶上(错误)
 {
    console.error(错误);
 }

于是人们想出了解决问题的对策,比如

但这些导致code一样简单,易于理解作为同步式code以上。

<击>那么,为什么不能对JavaScript的编译器/间preters只是不是在我们目前所知道的堵的语句块? 那么,为什么对JavaScript的编译器/间preters处理上面好像我们在一个异步的风格写它的语法同步是不可能的?

例如,在处理 getSomething()上面,编译器/间preTER可能只是说:这种说法是[文件系统/网络资源的调用/ ...],所以我会记下听从呼叫并在此期间获得的,在我的事件循环凡是的反应。当调用返回时,可以继续执行到 DoSomething的()

您仍然会保持所有流行的JavaScript运行时环境的基本特征


  • 单线程

  • 事件循环

  • 阻塞操作(I / O,网络,等待计时器)处理异步

这是只是一个调整的语法,这将允许跨preTER在code的任何给定的位,每当它检测到一个异步操作暂停执行,而是需要回调,$ C $ ç刚刚从该行继续异步调用后,当调用返回。

由于杰里米


  

有什么的JavaScript运行,将pemptively $ P $
  暂停给定任务的执行,允许一些其他的code执行
  一会儿,然后恢复原来的任务


为什么不呢? (如,为什么不能会有?......我没有兴趣在历史课)

为什么开发商要关心的陈述是否阻塞或不?计算机是自动化的东西,人类是在(例如写非阻塞code)错误。

您可以或许与实现它


  • 就像一份声明<罢工> 使用noblock; (有点像使用严格; )打开这个模式code的一整页。编辑:使用noblock;是一个不错的选择,而且误导了一些积极答复,我试图改变干脆常见的JavaScript运行时的性质。类似使用syncsyntax'; 可能更好地描述它

  • 某种并行(FN,FN,...)的; 语句让你而在使用syncsyntax运行的东西并行;模式 - 例如,允许多个异步活动即将拉开序幕一次

  • 编辑:一个简单的同步式的语法等待(),这将被用来代替的setTimeout()使用syncsyntax;模式

编辑:

作为一个例子的,而不是写(标准回调版本)

 函数fnInsertDB(MyString的,fnNextTask){
  fnDAL(插入TBL(场)VALUES('+ +的myString');,函数(recordId所){
    fnNextTask(recordId所);
  });
}fnInsertDB('东西',fnDeleteDB);

您可以写

 使用syncsyntax';功能fnInsertDB(MyString的){
  返回fnDAL(插入TBL(场)VALUES('+的myString');'); //返回的recordId
}VAR的recordId = fnInsertDB(东西);
fnDeleteDB(recordId所);

syncsyntax 版本将处理完全相同的方式与标准版相同,但它更容易理解程序员打算什么(只要你明白, syncsyntax 暂停作为上讨论了这个code)执行。


解决方案

  

那么,为什么不能对JavaScript的编译器/间preters只是不是在我们目前所知道的堵?

语句块

由于并发控制的。我们的希望的他们阻拦,让(在JavaScript的单线程的性质),我们是从的竞争条件,虽然我们仍然在执行它改变了我们功能的状态。我们不能有一个跨preTER,在任意声明/ EX pression暂停当前函数的执行,并与程序的某些其他部分恢复。

例如:

 功能银行(){
    this.savings = 0;
}
Bank.prototype.transfer =功能(howMuch){
    VAR储蓄= this.savings;
    this.savings =积蓄+ howMuch(); //我们预计`howMuch()`是堵
}

同步code:

  VAR组=新银行();
的setTimeout(函数(){
    bank.transfer(提示); //进入5
    警报(bank.savings); // 5
},0);
的setTimeout(函数(){
    bank.transfer(提示); //进入3
    警报(bank.savings); // 8
},100);

异步,任意无阻塞code:

 函数guiPrompt(){
    使用noblock
    //开放的形式
    //等待用户输入
    //关闭形式
    返回输入;
}
VAR银行=新银行();
的setTimeout(函数(){
    bank.transfer(guiPrompt); //进入5
    警报(bank.savings); // 5
},0);
的setTimeout(函数(){
    bank.transfer(guiPrompt); //进入3
    警报(bank.savings); // 3 // WTF?
},100);


  

    

有什么的JavaScript运行,将preemptively暂停特定任务的执行,允许一些其他的code了一会儿执行,然后恢复原来的任务


  
  
  

为什么不呢?


有关的简单性和安全性,见上文。 (而且,对于历史的教训:那怎么它只是做)

不过,这不再是真实的。随着ES6发电机,还有的东西,可以让你明确地暂停当前功能发电机的执行:在收益关键字。

随着语言的发展,也有异步伺机计划ES7 关键字。


  

发电机[...不...]导致code一样简单,易于理解如上同步code。


但他们做的!它甚至正确的文章:

 暂停(功能*(){
// ^使用noblock - 这个功能不连续运行
    尝试{
        无功富=产量getSomething();
// ^^^^^异步调用不阻塞线程
        VAR栏= DoSomething的(富);
        的console.log(巴);
    }赶上(错误){
        console.error(错误);
    }
})


也有对这个问题一个很好的文章在这里: http://howtonode.org/generators- VS-纤维

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

解决方案

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

这篇关于为什么不能流行的JavaScript运行时处理同步,异步看剧本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆