[英]Why is this async function not behaving asynchronously?
我正在学习 Javascript。 我不习惯异步编程,所以在这里很难。 这是我的代码:
var x = 0; async function increment(x) { ++x; for (var i = 0; i < 999999999; i = i + 1); console.log('value of x is: ' + x); }; increment(x); console.log('Out of the function');
期望:“超出功能”会立即打印出来。 'x 的值...' 需要一些时间。
现实:“x 的值...”在延迟后首先打印。 然后打印'Out of the function'。
我的问题是,为什么不异步调用 increment() ? 为什么它会阻止最后一个 console.log?
TL;DR:您必须在 async 函数中await something
才能使其异步。
var x = 0;
async function increment(x) {
await null; // <-- ADD THIS LINE
++x;
for (var i = 0; i < 10; i = i + 1);
console.log('value of x is: ' + x);
};
increment(x);
console.log('Out of the function');
更长的版本:
首先让我们澄清一件事:JS 运行时是基于事件循环的单线程运行时,这意味着没有并发/并行代码执行(除非您使用Worker
或child_process
,这是另一个主题)。
现在到异步部分。 async-await
只是一个方便的语法糖,它在底层使用Promise
和Generator
,后者又调用 platfrom 提供的事件循环调度 API。 在 Node.js 中,API 是process.nextTick
,而在浏览器中它是setImmediate
。
通过这些 API 调度作业,缓存在微任务队列中,空闲时由事件循环点击并执行。 因此,异步实际上只是调度。
有了这些知识,让我们回到你的案例。
async function
关键字做了两件事:
Promise
await
关键字实际调度部分发生在您使用await
关键字时。 它的作用是将计划任务发送到微任务队列,这将始终是对Promise.then()
调用的回调(在上面的示例中,我发送null
,它将被自动包装为Promise.resolve(null)
),然后暂停当前函数的执行,并等到该 promise 解决后再继续执行其余函数。
因此,如果您不使用await
关键字涉及事件循环调度程序,则执行顺序将保持正常。 从而解释你的情况。
如果您确实了解async
函数只是Promise
周围的语法糖,那么下一个常见的误解是new Promise(callback)
的执行顺序。
情况1:
new Promise((resolve) => {
console.log('Bob comes first!')
resolve(null)
})
console.log('Alice comes first!')
问:谁先来?
答:鲍勃先来。
案例二:
new Promise((resolve) => {
resolve(null)
}).then(() => console.log('Bob comes first!'))
console.log('Alice comes first!')
问:谁先来?
A : 这次爱丽丝先来。
案例 1 对应于您的代码。 async
将函数包装到一个 Promise 的回调中,但如果你不.then()
,该回调会立即按正常顺序执行。
案例 2 对应于我的await null
示例。 它将函数体分成两部分,一个在new Promise(callback)
中,其余在promise.then(callback)
中。 并且后者的执行顺序被推迟。
async
函数没有await
,因此函数将同步运行。 如果没有提供 await,javascript 不会抛出任何错误。
来自MDN
可以认为异步函数的主体被零个或多个等待表达式分割。 顶级代码,直到并包括第一个等待表达式(如果有),都是同步运行的。 这样,没有 await 表达式的 async 函数将同步运行
将其转换为如下所示的内容,您将看到预期的行为:
var x = 0; async function increment(x) { ++x; await setTimeout(function() { for (var i = 0; i < 999999999; i = i + 1); }); console.log('value of x is: ' + x); }; increment(x); console.log('Out of the function');
因为我想 JavaScript 不是多线程的。
您可以尝试使用 JQuery 方法(也许)或了解 Web Workers 我在谷歌上找到的第一个资源: https ://medium.com/techtrument/multithreading-javascript-46156179cf9a
那是因为异步函数并不意味着它总是最后结束。
将异步 console.log 包装在 setTimeout 中,您将首先看到最后一个 console.log 打印。
var x = 0; async function increment(x) { ++x; setTimeout(() => { console.log('value of x is: ' + x); }, 1000); }; increment(x); console.log('Out of the function');
这是一个小提琴: https ://jsfiddle.net/Ldjma3s8/
你应该使用等待。 来自官方 JS 文档:“关键字 await 使 JavaScript 等到该承诺完成并返回其结果。”
此外,如果它看起来有点奇怪,但您可以通过以下方式实现您的结果:
const x = 0;
async function f(x) {
try {
++x;
for (i = 0; i < 999; i = i + 1)
console.log('value of x is:', await i);
} catch (e) {
console.log('error', e);
}
};
f(x);
console.log('Out');
async 关键字使函数返回一个承诺或“thenable”。 您需要等待您的承诺增量。
提出了顶级等待,但在我们拥有它之前,您需要将您的调用放在另一个异步函数中或使用它。
https://github.com/tc39/proposal-top-level-await
var x = 0;
async function increment(x) {
++x;
for (var i = 0; i < 999999999; i = i + 1);
console.log('value of x is: ' + x);
};
async function waitThenLog() {
await increment(x);
console.log('Out of the function');
}
waitThenLog();
// or...
increment(x).then(() => console.log('Out of the function'));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.