pos*_*est 8 javascript error-handling asynchronous node.js ecmascript-6
正如牛仔在这里的评论中所说,我们都想"以类似于这样的风格编写[非阻塞JavaScript]异步代码:
try
{
var foo = getSomething(); // async call that would normally block
var bar = doSomething(foo);
console.log(bar);
}
catch (error)
{
console.error(error);
}
Run Code Online (Sandbox Code Playgroud)
"
所以人们已经提出了解决这个问题的方法
但是这些都没有导致代码像上面的同步样式代码一样简单易懂.
那么为什么javascript编译器/解释器不能阻止我们目前称为"阻塞"的语句呢?那么,为什么javascript编译器/解释器无法处理AS上面的同步语法,如果我们以异步方式编写它?"
例如,在getSomething()
上面的处理中,编译器/解释器可以只说"这个语句是对[文件系统/网络资源/ ...]的调用,所以我会做一个注释来听取来自该调用的响应和同时继续我的事件循环中的任何东西".当调用返回时,执行可以继续doSomething()
.
您仍然可以维护流行的JavaScript运行时环境的所有基本功能
这只是对语法的一种调整,这将允许解释器在IT DETECTS一个异步操作时暂停执行任何给定的代码位,而不是需要回调,代码只是在调用异步调用后从行继续执行回报.
正如杰里米所说
JavaScript运行时中没有任何内容可以预先暂停执行给定任务,允许其他代码执行一段时间,然后恢复原始任务
为什么不?(如同,"为什么不能有?"......我对历史课不感兴趣)
为什么开发人员必须关心语句是否阻塞?计算机用于自动化人类擅长的东西(例如编写非阻塞代码).
您也许可以实现它
"use noblock"
; "use strict";
)打开整个代码页的"模式".编辑:"use noblock"
; 这是一个糟糕的选择,误导了一些回答者,我试图完全改变常见的JavaScript运行时的性质.喜欢的东西'use syncsyntax';
可能会更好地描述它.parallel(fn, fn, ...);
语句,允许你在进行中并行运行"use syncsyntax"
; 模式 - 例如,允许一次启动多个异步活动wait()
,这将用来代替setTimeout()
在"use syncsyntax"
; 模式编辑:
作为一个例子,而不是写(标准回调版)
function fnInsertDB(myString, fnNextTask) {
fnDAL('insert into tbl (field) values (' + myString + ');', function(recordID) {
fnNextTask(recordID);
});
}
fnInsertDB('stuff', fnDeleteDB);
Run Code Online (Sandbox Code Playgroud)
你可以写
'use syncsyntax';
function fnInsertDB(myString) {
return fnDAL('insert into tbl (field) values (' + myString ');'); // returns recordID
}
var recordID = fnInsertDB('stuff');
fnDeleteDB(recordID);
Run Code Online (Sandbox Code Playgroud)
该syncsyntax
版本的处理方式与标准版本的处理方式完全相同,但更容易理解程序员的意图(只要您了解syncsyntax
暂停执行此代码的执行情况).
Ber*_*rgi 13
那么为什么javascript编译器/解释器不能阻止我们目前称为"阻塞"的语句呢?
因为并发控制.我们希望它们被阻塞,以便(在JavaScript的单线程特性中)我们可以安全地从竞争条件中改变我们的函数状态,同时我们仍在执行它.我们不能有一个解释器在任何语句/表达式中暂停当前函数的执行,并且恢复程序的某些不同部分.
例:
function Bank() {
this.savings = 0;
}
Bank.prototype.transfer = function(howMuch) {
var savings = this.savings;
this.savings = savings + +howMuch(); // we expect `howMuch()` to be blocking
}
Run Code Online (Sandbox Code Playgroud)
同步代码:
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);
Run Code Online (Sandbox Code Playgroud)
异步,任意非阻塞代码:
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);
Run Code Online (Sandbox Code Playgroud)
JavaScript运行时中没有任何内容可以预先暂停执行给定任务,允许其他代码执行一段时间,然后恢复原始任务
为什么不?
为简单和安全,请参见上文.(并且,对于历史课:这就是它刚刚完成的方式)
但是,这已不再适用.随着ES6发电机,还有就是一些可以让你明确暂停当前的执行函数发生器:该yield
关键字.
随着语言的发展,ES7 也计划async
和await
关键字.
生成器[...不...]导致代码与上面的同步代码一样简单易懂.
但是他们做到了!这篇文章甚至是正确的:
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);
}
})
Run Code Online (Sandbox Code Playgroud)
这里还有一篇关于这个主题的非常好的文章:http://howtonode.org/generators-vs-fibers
为什么不?没有原因,只是还没有完成。
在 2017 年,ES2017已经做到了:函数可以用于非阻塞地等待 Promise 的结果。如果返回一个 Promise(注意)并且它位于函数内部,您可以这样编写代码:async
await
getSomething
await
async
try
{
var foo = await getSomething();
var bar = doSomething(foo);
console.log(bar);
}
catch (error)
{
console.error(error);
}
Run Code Online (Sandbox Code Playgroud)
(我假设您只想getSomething
异步,但它们都可以。)
实时示例(需要最新的浏览器,例如最近的 Chrome):
try
{
var foo = await getSomething();
var bar = doSomething(foo);
console.log(bar);
}
catch (error)
{
console.error(error);
}
Run Code Online (Sandbox Code Playgroud)
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);
}
})();
Run Code Online (Sandbox Code Playgroud)
您已使用 NodeJS 标记了您的问题。如果将 Node API 包装在 Promise 中(例如,使用promisify),则可以编写异步运行的漂亮、直接、同步的代码。