一尘不染

为何流行的JavaScript运行时无法处理看起来像同步的异步脚本?

node.js

正如牛仔在此处的评论中所说的,我们所有人都想以类似于以下的样式来编写[非阻塞JavaScript]异步代码:

 try 
 {
    var foo = getSomething();   // async call that would normally block
    var bar = doSomething(foo);  
    console.log(bar); 
 } 
 catch (error) 
 {
    console.error(error);
 }

因此人们提出了解决该问题的方法,例如

但是,这些都不比上面的同步样式代码更简单易懂。

那么,为什么JavaScript编译器/解释器无法仅不阻塞我们当前称为“阻塞”的语句呢?
那么,如果我们以异步方式编写的话,为什么JavaScript编译器/解释器无法处理AS之上的同步语法呢?”

例如,经过getSomething()上面的处理,编译器/解释器可能会说“此语句是对[文件系统/网络资源/
…]的调用,因此我将做一个笔记来监听来自该调用的响应,并在同时继续处理我的事件循环”。调用返回时,执行可以进行到doSomething()

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

  • 单螺纹
  • 事件循环
  • “异步”处理的阻塞操作(I / O,网络,等待计时器)

这只是语法上的一个调整,这将允许解释器在IT进行异步操作检测时暂停对任何给定代码的执行,并且不需要回调,而是仅在异步调用后的代码行中继续执行代码,而无需进行回调返回。

正如杰里米所说

JavaScript运行时中没有什么可以抢先暂停给定任务的执行,允许其他一些代码执行一段时间,然后继续执行原始任务

为什么不?(例如,“为什么不可以?” …我对历史课程不感兴趣)

开发人员为什么要关心语句是否被阻塞?计算机用于自动化人类不擅长的事物(例如,编写非阻塞代码)。

你也许可以用

  • 像这样的陈述 "use noblock" ; (有点像"use strict";)打开整个页面代码的“模式”。编辑:"use noblock"; 是一个错误的选择,并误导了一些我试图完全改变普通JavaScript运行时性质的答案。类似的东西'use syncsyntax';可能会更好地描述它。
  • 一种parallel(fn, fn, ...);允许您在运行中并行运行的语句"use syncsyntax"; 模式-例如,允许一次启动多个异步活动
  • 编辑:一种简单的同步样式语法wait(),该语法将代替setTimeout()in "use syncsyntax"; 模式

编辑:

例如,代替编写(标准回调版本)

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所讨论的代码会暂停执行)。


阅读 407

收藏
2020-07-07

共1个答案

一尘不染

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

在2017年,它 ES2017中完成:async函数可以用于await等待,无阻塞地等待承诺的结果。如果getSomething返回promise(请注意await)并且位于async函数内部,则可以这样编写代码:

try 
{
    var foo = await getSomething();
    var bar = doSomething(foo);  
    console.log(bar); 
} 
catch (error) 
{
    console.error(error);
}

(我曾假设您只打算getSomething异步,但两者都可能是异步的。)

实时示例(需要最新的浏览器,例如最新的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包装在Promise中(例如,使用promisify),则可以编写异步运行的漂亮的直接同步代码。

2020-07-07