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

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

问题描述

正如 cowboy 在此处的评论中所说,我们都想编写 [非阻塞 JavaScript] 异步代码类似这样的风格:

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.

那么为什么 javascript 编译器/解释器不可能只阻止我们目前称为阻塞"的语句? 那么为什么 javascript 编译器/解释器不可能像我们用异步风格编写的那样处理上面的同步语法?"

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?"

例如,在处理上面的 getSomething() 时,编译器/解释器可以只说这个语句是对 [文件系统/网络资源/...] 的调用,所以我会记下该电话的响应,同时继续处理我的事件循环中的任何内容".当调用返回时,可以继续执行doSomething().

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

您仍将保留流行的 JavaScript 运行时环境的所有基本功能

You would still maintain all of the basic features of popular JavaScript runtime environments

  • 单线程
  • 事件循环
  • 异步"处理的阻塞操作(I/O、网络、等待计时器)

这只是对语法的一个调整,它允许解释器在检测到异步操作时暂停任何给定的代码位的执行,并且不需要回调,代码只是在异步调用之后从行继续当呼叫返回时.

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.

正如 Jeremy 所说

JavaScript 运行时中没有任何东西可以抢占暂停给定任务的执行,允许其他一些代码执行一会,然后恢复原来的任务

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

你也许可以用

  • "use noblock";(有点像"use strict";)这样的语句来打开这个模式"一整页代码."use noblock";是一个糟糕的选择,并误导了一些回答者我试图完全改变常见 JavaScript 运行时的性质.诸如 'use syncsyntax'; 之类的东西可能会更好地描述它.
  • 某种parallel(fn, fn, ...); 语句允许您在use syncsyntax" 中并行运行事物;模式 - 例如允许同时启动多个异步活动
  • 一个简单的同步风格语法 wait(),在 "use syncsyntax" 中将用于代替 setTimeout();模式
  • a statement like "use noblock"; (a bit like "use strict";) to turn this "mode" on for a whole page of code. "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
  • a simple sync-style syntax wait(), which would be used instead of setTimeout() in "use syncsyntax"; mode

举个例子,而不是写(标准回调版本)

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

你可以写

'use syncsyntax';

function fnInsertDB(myString) {
  return fnDAL('insert into tbl (field) values (' + myString ');');  // returns recordID
}

var recordID = fnInsertDB('stuff'); 
fnDeleteDB(recordID);

syncsyntax 版本的处理方式与标准版本完全相同,但更容易理解程序员的意图(只要你理解 syncsyntax如上所述执行此代码).

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

推荐答案

为什么不呢?没有理由,只是没有完成.

Why not? No reason, it just hadn't been done.

在 2017 年,它已经ES2017:async 函数 可以使用 await 非阻塞地等待 promise 的结果.如果getSomething 返回一个promise(注意await)并且这是在async 函数中,您可以像这样编写代码:

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

(我已经假设您只希望 getSomething 是异步的,但它们都可能是.)

(I've assumed there that you only intended getSomething to be asynchronous, but they both could be.)

实时示例(需要最新的浏览器,如最近的 Chrome):

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.

您已使用 NodeJS 标记了您的问题.如果你将 Node API 封装在 promises 中(例如,使用 promisify),你可以写好异步运行的直截了当的同步代码.

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.

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

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