简体   繁体   English

Javascript 异步执行的机制

[英]Mechanics of Javascript Asynchronous execution

Can someone please explain the mechanics behind the asynchronous behavior of javascript, specifically when it comes to a.subscribe(), or provide a link that would help me understand what's really going on under the hood?有人可以解释一下 javascript 的异步行为背后的机制,特别是在涉及 a.subscribe() 时,或者提供一个链接来帮助我了解引擎盖下到底发生了什么?

Everything appears to be single-threaded, then I run into situations that make it either multi-threaded, or seem multi-threaded, because I still can't shake this feeling I'm being fooled.一切似乎都是单线程的,然后我遇到了使其成为多线程或看起来多线程的情况,因为我仍然无法摆脱这种被愚弄的感觉。

Everything seems to run perfectly synchronously, one instruction at a time, until I call.subscribe().一切似乎都完美地同步运行,一次一条指令,直到我调用.subscribe()。 Then, suddenly, something happens - it returns immediately, and somehow the next outside function runs even though the subscription code has not yet.然后,突然间,发生了一些事情——它立即返回,并且不知何故,即使订阅代码还没有,function 之外的下一个运行。 This feels asynchronous to me, how does the browser keep things straight - if not threads, can someone please explain the mechanics in play that is allowing this to occur?这对我来说感觉是异步的,浏览器如何保持正常 - 如果不是线程,有人可以解释一下允许这种情况发生的机制吗?

I also notice something happens with debug stepping, I can't step in to the callback, I can only put a breakpoint within it.我还注意到调试步进发生了一些事情,我无法进入回调,我只能在其中放置一个断点。 In what order should I really expect things to occur?我真正期望事情发生的顺序是什么?

Your Javascript itself runs single threaded unless you're talking about WebWorkers (in the browser) or WorkerThreads (in nodejs).您的 Javascript 本身运行单线程,除非您在谈论 WebWorkers(在浏览器中)或 WorkerThreads(在 nodejs 中)。

But, many functions you call or operations you initiate in Javascript can run separate from that single threaded nature of your Javascript.但是,您在 Javascript 中调用的许多函数或启动的操作可以与 Javascript 的单线程特性分开运行。 For example, networking is all non-blocking and asynchronous.例如,网络都是非阻塞和异步的。 That means that when you make a call to fetch() in the browser of http.get() in nodejs, you are initiating an http request and then the mechanics of making that request and receiving the response are done independent of your Javascript.这意味着当您在 nodejs 中的http.get()的浏览器中调用fetch()时,您正在启动 http 请求,然后发出该请求和接收响应的机制独立于您的 Z9E1Z13B69D1D15ACA9377 Here are some example steps:以下是一些示例步骤:

  1. You make a call to fetch() in the browser to make an http request to some other host.您在浏览器中调用fetch()以向其他主机发出 http 请求。
  2. The code behind fetch, sends out the http request and then immediately returns. fetch 后面的代码发出 http 请求,然后立即返回。
  3. Your Javascript continues to execute (whatever you had on the lines of code immediately after the fetch() call will execute.您的 Javascript 继续执行(无论您在fetch()调用后立即执行的代码行中的内容都将执行。
  4. Sometime later, the response from the fetch() call arrives back on the network interface.稍后,来自fetch()调用的响应返回到网络接口。 Some code (internal to the Javascript environment) and independent from your single thread of Javascript sees that there's incoming data to read from the http response.一些代码(在 Javascript 环境内部)并且独立于 Javascript 的单线程,可以看到从 http 响应中读取的传入数据。 When that code has gathered the http response, it inserts an event into the Javascript event queue.当该代码收集到 http 响应时,它会将一个事件插入到 Javascript 事件队列中。
  5. When the single thread of Javascript has finished executing whatever event it was executing, it checks the event queue to see if there's anything else to do.当 Javascript 的单线程执行完它正在执行的任何事件时,它会检查事件队列以查看是否还有其他事情要做。 At some point, it will find the event that signified the completion of the previous fetch() call and there will be a callback function associated with that event.在某个时候,它会找到表示上一次fetch()调用完成的事件,并且将有一个与该事件关联的回调 function。 It will call that callback which will resolve the promise associated with the fetch() call which will cause your own Javascript in the .then() handler for that promise to run and your Javascript will be presented the http response you were waiting for. It will call that callback which will resolve the promise associated with the fetch() call which will cause your own Javascript in the .then .then() handler for that promise to run and your Javascript will be presented the http response you were waiting for.

Because these non-blocking, asynchronous operations (such as networking, timers, disk I/O, etc...) all work in this same manner and can proceed independent of your Javascript execution, they can run in parallel with your Javascript execution and many of them can be in flight at the same time while your Javascript is doing other things.因为这些非阻塞、异步操作(例如网络、计时器、磁盘 I/O 等)都以相同的方式工作,并且可以独立于您的 Javascript 执行进行,它们可以与您的 Javascript 执行并行运行,并且他们中的许多人可以同时飞行,而您的 Javascript 正在做其他事情。 This may sometimes give the appearance of multiple threads and there likely are some native code threads participating in some of this, though there is still only one thread of your Javascript (as long as we're not talking about WebWorkers or WorkerThreads).这有时可能会出现多个线程,并且可能有一些本机代码线程参与其中,尽管您的 Javascript 仍然只有一个线程(只要我们不是在谈论 WebWorkers 或 WorkerThreads)。

The completion of these asynchronous operations is then synchronized with the single thread of Javascript via the event queue.这些异步操作的完成然后通过事件队列与Javascript的单线程同步。 When they finish, they place an event in the event queue and when the single thread of Javascript finishes what it was last doing, it grabs the next event from the event queue and processes it (calling a Javascript callback).当他们完成时,他们在事件队列中放置一个事件,当 Javascript 的单线程完成它最后一次做的事情时,它从事件队列中获取下一个事件并处理它(调用 Javascript 回调)。

I also notice something happens with debug stepping, I can't step in to the callback, I can only put a breakpoint within it.我还注意到调试步进发生了一些事情,我无法进入回调,我只能在其中放置一个断点。 In what order should I really expect things to occur?我真正期望事情发生的顺序是什么?

This is because the callback isn't called synchronously.这是因为回调不是同步调用的。 When you step over the function that you passed a callback to, it executes that function and it returns.当您跨过您传递回调的 function 时,它会执行 function 并返回。 Your callback is not yet called.您的回调尚未调用。 So, the debugger did exactly what you asked it to do.因此,调试器完全按照您的要求进行了操作。 It executed that function and that function returned.它执行了 function 和 function 返回。 The callback has not yet executed.回调尚未执行。 Your are correct that if you want to see the asynchronous callback execute, you need to place a breakpoint in it so when it does get called some time in the future, the debugger will then stop there and let you step further.你是对的,如果你想看到异步回调的执行,你需要在其中放置一个断点,这样当它在未来的某个时间被调用时,调试器就会停在那里,让你更进一步。 This is a complication of debugging asynchronous things, but you get used to it after awhile.这是调试异步事物的复杂性,但过一段时间你就会习惯它。

Everything appears to be single-threaded, then I run into situations that make it either multi-threaded, or seem multi-threaded, because I still can't shake this feeling I'm being fooled.一切似乎都是单线程的,然后我遇到了使其成为多线程或看起来多线程的情况,因为我仍然无法摆脱这种被愚弄的感觉。

This is because there can be many asynchronous operations in flight at the same time as they aren't running your Javascript while they are doing their thing.这是因为可能有许多异步操作同时进行,因为他们在做他们的事情时没有运行您的 Javascript。 So, there's still only one thread of Javascript, even though there are multiple asynchronous operations in flight.所以,Javascript 的线程仍然只有一个,即使有多个异步操作在运行。 Here's a code snippet:这是一个代码片段:

console.log("starting...");
fetch(host1).then(result1 => { console.log(result1)});
fetch(host2).then(result2 => { console.log(result2)});
fetch(host3).then(result3 => { console.log(result3)});
fetch(host4).then(result4 => { console.log(result4)});
console.log("everything running...");

If you run this, you will see something like this in the console:如果你运行它,你会在控制台中看到类似这样的东西:

starting...
everything running...
result1
result2
result3
result4

Actually, the 4 results may be in any order relative to one another, but they will be after the first two lines of debug output.实际上,这4个结果可能相对于彼此以任何顺序排列,但它们将在调试output的前两行之后。 In this case, you started four separate fetch() operations and they are running independent of your Javascript.在这种情况下,您启动了四个单独的fetch()操作,它们独立于您的 Javascript 运行。 In fact, your Javascript is free to do other things while they run.事实上,您的 Javascript 在运行时可以自由地做其他事情。 When they finish and when your Javascript isn't doing anything else, your four .then() handlers will each get called at the appropriate time.当它们完成并且您的 Javascript 没有做任何其他事情时,您的四个.then()处理程序将在适当的时间分别被调用。

When the networking behind each fetch() operation finishes, it will insert an event in the Javascript event queue and if your Javascript isn't doing anything at the time, the insertion of that event will wake it up and cause it to process that completion event.当每个fetch()操作背后的网络完成时,它将在 Javascript 事件队列中插入一个事件,如果您的 Javascript 当时没有做任何事情,该事件的插入将唤醒它并使其处理该完成事件。 If it was doing something at the time, then when it finishes that particular piece of Javascript and control returns back to the system, it will see there's an event waiting in the event queue and will process it, calling your Javascript callback associated with that event.如果它当时正在做某事,那么当它完成 Javascript 的特定部分并将控制权返回到系统时,它将看到事件队列中有一个事件等待并处理它,调用与该事件关联的 Javascript 回调.

Search for articles or videos on the “JavaScript Event Loop”.在“JavaScript Event Loop”上搜索文章或视频。 You'll find plenty of them.你会发现很多。 Probably go through a few of them and it will start to make sense (particularly the single-threaded aspect of it)可能 go 通过其中一些,它会开始有意义(特别是它的单线程方面)

I found this one with a quick search, and it does a good, very high-level walkthrough.我通过快速搜索找到了这个,它做了一个很好的、非常高级的演练。

The JavaScript Event Loop explained JavaScript 事件循环解释

The main impact of JavaScript single threading is that your code is never pre-emptively interrupted to execute code on another thread. JavaScript 单线程的主要影响是您的代码永远不会被抢先中断以在另一个线程上执行代码。

It may seem that some code is being skipped, but close attention to the syntax will show that what is being “skipped” is just a callback function or closure to be called at a time in the future (when it will be placed into the event queue and processed single-threadedly, itself).似乎有些代码被跳过了,但仔细观察语法会发现,被“跳过”的只是一个回调 function 或将来一次调用的闭包(当它将被放入事件中时)队列和单线程处理,本身)。

Careful, it can be tricky to follow nested callbacks.小心,遵循嵌套回调可能会很棘手。

Probably also look into Promises and async /await ('just syntactic convenience on the event loop, but can really help code readability)可能还会研究 Promises 和 async /await ('只是事件循环的语法便利,但确实有助于代码可读性)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM