Aja*_*ish 2 javascript asynchronous node.js
我是 Javascript 和异步编程的新手,有些事情让我感到困惑,请指出我学习中的错误。
setTimeout是异步的。以上如有错误,请指出。
异步函数的回调被放入消息队列中并通过事件循环执行。
不。
通常有两种异步函数 - 一种在完成时需要某种回调来运行,另一种则生成 Promise 作为结果。
这是基于回调的函数的示例:
setTimeout(() => console.log("foo"), 0);
console.log("bar");
/* output:
bar
foo
*/Run Code Online (Sandbox Code Playgroud)
setTimeout将延迟稍后执行的回调。即使超时为零毫秒,它仍然会安排回调,直到当前执行完成之后,因此顺序是:
setTimeout安排回调。console.log("bar")运行。console.log("foo")。没有消息队列,有一个要执行的任务队列。作为一个简短的概述,事件循环从队列中获取一个任务并执行它直至完成,然后获取下一个任务并执行它直至完成,等等。一个简单的伪代码表示是:
while(true) {
if (eventQueue.hasNext()) {
task = eventQueue.takeNext();
task();
}
}
Run Code Online (Sandbox Code Playgroud)
setTimeout话虽如此,事件循环比许多其他基于回调的函数更具影响力。基于回调的函数的其他示例是用于文件系统访问的 jQuery$.ajax()或 Node.jsfs模块(其非承诺 API)。他们和其他人也接受稍后执行的回调,但边界因素不是事件循环,而是函数执行的任何底层操作。何时$.ajax() 调用回调取决于网络速度、延迟和响应请求的服务器。因此,虽然回调将由事件循环执行,但其他一切也是如此。所以,这没什么特别的。这里只有setTimeout一个更特殊的交互,因为根据可用的任务,计时可能不精确 - 如果您安排某些任务在 10 毫秒内运行,而某些任务需要 12 毫秒才能完成,则安排的回调将不会按时运行setTimeout。
这是一个例子:
while(true) {
if (eventQueue.hasNext()) {
task = eventQueue.takeNext();
task();
}
}
Run Code Online (Sandbox Code Playgroud)
(为了便于说明,我现在省略了很多细节。)
从技术上讲,Promise 是针对处理异步操作而定制的回调的抽象。Promise 的方法.then()接受回调,并在Promise 解决后执行它,这也会在异步操作完成后发生。因此,我们可以按照正确的顺序一起执行:
async function fn(print) {
await "magic for now";
console.log(print);
}
fn("foo")
.then(() => console.log("bar"));
/* output:
foo
bar
*/Run Code Online (Sandbox Code Playgroud)
在某种程度上,Promise 是一种回调,因为它们是用来替代 Promise 并以大致相同的方式执行的。您仍然可以传递回调以在成功或失败时执行。但它们不仅仅是回调。
无论如何,给予 Promise 的回调仍然会延迟:
async function fn(print) {
await "magic for now";
console.log(print);
}
fn("foo");
console.log("bar");
/* output:
bar
foo
*/Run Code Online (Sandbox Code Playgroud)
但不是通过与所setTimeout使用的相同的事件队列。有两个队列:
setTimeout将东西放入其中,所有 UI 交互也添加到此处。当事件循环运行时,微任务队列(即promise)具有最高优先级,然后是宏任务队列。这导致:
Promise.resolve()
.then(() => console.log("foo"));
console.log("bar");
/* output:
bar
foo
*/Run Code Online (Sandbox Code Playgroud)
无论如何,我认为我不太愿意说基于 Promise 的函数通过回调来工作。有点是的,但是是在还原论的意义上。
异步执行是非阻塞的,通过事件循环完成。
不。
首先,让我们明确一点 - 阻塞行为是指环境正忙于执行某些操作时。通常在该执行期间不能运行其他代码。因此,进一步的代码将被阻止运行。
我们以这段代码为例:
setTimeout(taskForLater, 5000);
while (somethingIsNotFinished()) {
tryToFinish();
}
Run Code Online (Sandbox Code Playgroud)
这里taskForLater将被安排在5秒内运行。但是,while循环会阻塞执行。由于不会运行其他代码,taskForLater因此可能会在 10 秒内运行(如果这是循环完成所需的时间)。
运行异步函数并不总是意味着它与当前代码并行运行。在大多数情况下,环境一次执行一件事。JavaScript 默认情况下没有多线程,并行执行是一种选择行为,例如通过使用工人。
这可能意味着几件事,但不清楚您引用的是哪一个:
在这两种情况下,引用的陈述都是错误的,但原因不同。
异步函数是承诺的语法糖。它们使用相同的机制,但只是以不同的方式呈现代码。然而,异步函数是阻塞的。附带说明一下,Promise 执行器(给予 Promise 构造函数的回调)也是如此。在这两种情况下,该函数都会运行并阻塞,直到有原因导致其暂停。演示它的最简单方法是使用异步函数 - 使用await 将暂停函数的执行并安排其余部分稍后完成。
全身都堵住了:
setTimeout(() => console.log("foo")); //3 - macrotask queue
Promise.resolve()
.then(() => console.log("bar")); //2 - microtask queue
console.log("baz"); //1 - current execution
/* output:
baz
bar
foo
*/Run Code Online (Sandbox Code Playgroud)
中间停顿一下:
setTimeout(taskForLater, 5000);
while (somethingIsNotFinished()) {
tryToFinish();
}
Run Code Online (Sandbox Code Playgroud)
需要澄清的是,可以等待任何值,而不仅仅是承诺。等待非承诺仍然会暂停并恢复执行,但由于没有什么可等待的,这将导致它成为微任务队列上的首要任务之一。
无论如何,执行异步函数的主体可能会阻塞。取决于什么操作。
当谈论“底层操作”时,大多数时候我们的意思是将控制权交给其他东西,例如浏览器或库。在这种情况下,当前的 JavaScript 环境不会完成该操作,我们称之为将执行操作并仅在操作完成时通知当前 JavaScript 环境的东西。例如,在浏览器中调用fetch将触发网络请求,但处理它的是浏览器,而不是我们的代码。所以它是非阻塞的,但不是在执行环境之外。
async function fn() {
console.log("foo");
console.log("bar");
}
fn();
console.log("baz");
/* output:
foo
bar
baz
*/Run Code Online (Sandbox Code Playgroud)
话虽如此,我们甚至无法概括给定的异步操作将做什么。它实际上可能会阻塞执行,至少会阻塞一段时间,或者可能完全在当前 JavaScript 环境的单独进程中执行。
像这样的函数
setTimeout是异步的。
是的。
虽然,它可能正在考虑是什么样的 setTimeout。是吗setInterval?它是基于回调的异步函数吗?问题在于定义开始变得循环“基于异步回调的函数(例如setTimeout异步函数)”。
并非每个接受回调的函数都是异步的。那些可能被认为类似于setTimeout。
异步函数是阻塞的,只有它们的回调是非阻塞的。
不。
如上所述,异步函数可能会阻塞。取决于他们具体做什么。例如$.ajax会使用浏览器发起网络请求,类似于fetch。如果$.ajax功能在准备请求时阻塞,但在发送请求后则不会阻塞。
该语句的第二个问题是,以非阻塞方式调用回调是不正确的——执行它们肯定会再次阻塞执行。回调是一个普通的 JavaScript 代码,当时间到来时将通过事件循环执行。当任务运行完成时,执行仍然被阻止。
如果您的意思是它们是非阻塞的,因为回调将被放入事件队列中,但这仍然不能保证。考虑以下说明性代码:
function myAsyncFunction(callback) {
const asyncResult = someAsynchronousNonBlockingOperation();
doStuff(result);
callback(result);
doMoreStuff(result);
}
Run Code Online (Sandbox Code Playgroud)
一旦someAsynchronousNonBlockingOperation()产生一个值,执行callback将不会被安排在以后执行,但将成为处理该结果的同步代码序列的一部分。因此,将稍后callback执行,但它本身不是一个任务,而是包含和 的整体任务的一部分。doStuffdoMoreStuff
| 归档时间: |
|
| 查看次数: |
531 次 |
| 最近记录: |