swoole 调用异步队列
JavaScript is a single threaded programming language. This means that only one piece of code can run at a time, on a single main thread, and everything else is blocked until an operation completes.
JavaScript是一种单线程编程语言。 这意味着一次只能在一个主线程上运行一段代码,而所有其他内容将被阻塞,直到操作完成。
But we don’t want to wait or get blocked for a certain asynchronous task to complete! Imagine scrolling through Instagram and not able to actually scroll until a particular feed is loaded completely. That would be really awful!
但是我们不想等待或被阻止完成某些异步任务! 想象一下,在Instagram中滚动,直到完全加载特定的提要才能真正滚动。 那真是太糟糕了!
Luckily, JavaScript is a non-blocking language, and this article is all about how things work under the hood.
幸运的是,JavaScript是一种非阻塞性语言,本文主要讨论事物的工作原理。
目录 (Table of Contents)
- Execution Context 执行上下文
- Call Stack 调用堆栈
- Task Queue 任务队列
- Job Queue 作业队列
- Event loop — How it all works together! 事件循环-如何协同工作!
执行上下文 (Execution Context)
Before we get into how JavaScript handles asynchronous tasks, one should know how exactly JavaScript code executes.
在我们开始研究JavaScript如何处理异步任务之前,应该先了解JavaScript代码是如何执行的。
Execution context is an abstract concept that holds information about the environment within which the current code is being executed.
执行上下文是一个抽象概念,其中包含有关在其中执行当前代码的环境的信息 。
Whenever a JavaScript file loads in the browser for the first time, a global execution context is created.
每当首次在浏览器中加载JavaScript文件时,都会创建一个全局执行上下文 。
Every-time we call/invoke a function, a new execution context gets created.
每次我们调用/调用一个函数时,都会创建一个新的执行上下文 。
When we return out from a function OR function body is completely executed, the execution context of that function is destroyed and garbage collected.
当我们从某个函数返回或函数主体完全执行时,该函数的执行上下文将被破坏并回收垃圾 。
Basically, 2 things happen(simultaneously) whenever a JavaScript code is executed in a given execution context —
基本上,每当在给定的执行上下文中执行JavaScript代码时,就会同时发生两件事-
Threading — JavaScript thread executes each line of code one at a time in a procedural manner.
线程化 -JavaScript线程以一种程序化方式一次执行每一行代码。
Memory — JavaScript creates new labels and store in memory, all the variable/function declarations for a given execution context
内存 -JavaScript创建新标签并将给定执行上下文的所有变量/函数声明存储在内存中
调用堆栈 (Call Stack)
A call stack is a mechanism for an interpreter (like the JavaScript interpreter in a web browser) to keep track of its place in a script that calls multiple functions — what function is currently being run and what functions are called from within that function, etc.
调用堆栈是一种解释器(例如Web浏览器中JavaScript解释器)在调用多个函数的脚本中跟踪其位置的机制-当前正在运行的函数以及在该函数中调用的函数,等等。 。
More precisely, Call stack helps us know inside which execution context our main thread currently is! Let that sink in.
更准确地说, 调用堆栈可帮助我们了解当前主线程位于哪个执行上下文中 ! 让它沉入。
We need to remember few things —
我们需要记住几件事-
The first thing that gets pushed on to our call stack is global execution context.
推送到我们的调用堆栈的第一件事是全局执行上下文。
Whenever a new function is invoked, i.e., when a new execution context is created, it is pushed on to the call stack
每当调用新函数时 ,即创建新的执行上下文时 ,都会将其压入调用堆栈
Whenever a function has finished executing, i.e, when the execution context is destroyed, it gets popped(removed) from the call stack.
每当函数完成执行时,即当执行上下文被破坏时,都会从调用堆栈中弹出 (删除)该函数。
- Call stack gets emptied, when the complete JavaScript code has been executed, i.e., when global execution is destroyed. 执行完完整JavaScript代码后,即销毁全局执行时,调用堆栈将被清空。
任务队列 (Task Queue)
To perform asynchronous tasks, JavaScript utilises WebAPIs
为了执行异步任务,JavaScript利用WebAPI
WebAPIs are part of the browser and not JavaScript runtime. So JavaScript runtime interfaces with WebAPIs and enables us to perform asynchronous tasks while not blocking the main thread at the same time!
WebAPI是浏览器的一部分,而不是JavaScript运行时。 因此,JavaScript运行时与WebAPI交互,使我们能够执行异步任务,而不会同时阻塞主线程!
Task Queue is a DS, which kicks in when we utilise any WebAPI.
Task Queue是一个DS,在我们使用任何WebAPI时都会启动。
In most of the cases, when we initiate an async task, we provide a callback function, which executes when the time taking async task completes. This callback function needs to get back to the Call Stack for getting executed. Now the question arises when do we exactly push this callback function to the CallStack?
在大多数情况下,当我们启动异步任务时,我们提供了一个回调函数 ,该函数在耗时的异步任务完成时执行。 该回调函数需要返回到调用堆栈才能执行。 现在出现问题了,我们何时将该回调函数准确地推入CallStack?
Basically,
基本上,
Whenever a async task completes, the callback function associated with the async task gets pushed to the Task Queue.
每当异步任务完成时,与异步任务关联的回调函数就会被推送到任务队列。
For example, consider setTimeout
example below —
例如,考虑下面的setTimeout
示例-
It is good to note that both
sayHello
andsayBye
are callback functions.最好注意,
sayHello
和sayBye
都是回调函数。- We trigger 2 setTimeout functions which triggers a timer in the browser. 我们触发了2个setTimeout函数,它们会在浏览器中触发一个计时器。
According to the 2nd parameter to
setTimeout
which is time in milliseconds, the timer gets completed, and the callback function gets pushed to the Task Queue.根据
setTimeout
的第二个参数(以毫秒为单位的时间),计时器完成,并且回调函数被推入任务队列。Hence Task Queue for the above example looks something like this — [
sayHello
,sayBye
]因此,上述示例的“任务队列”看起来像这样— [
sayHello
,sayBye
]
作业队列 (Job Queue)
ES6 introduced the concept of the Job Queue, which is used by Promises (also introduced in ES6). It’s a way to execute the result of an async function as soon as possible, rather than being put at the end of the call stack.
ES6引入了作业队列的概念, Promises (也在ES6中引入了) 使用了该队列。 这是为尽快执行异步函数的结果,而不是在调用堆栈的一端放的方式。
So whenever we use Promise for an async task, after the promise is resolved, the callback associated with the promise is pushed to the Job Queue.
因此,每当我们将Promise用于异步任务时,在解决了Promise后,与Promise关联的回调都会被推送到Job Queue。
For example — If a promise is resolved and our Call Stack is not empty, i.e., our main thread is inside some execution context, then after the current execution context is destroyed, and no more sync code is left to execute, the next thing that will be pushed on to our Call Stack will be from our Job Queue.
例如-如果一个Promise被解决并且我们的调用栈不为空,即我们的主线程在某个执行上下文内,那么在当前执行上下文被销毁并且不再有任何同步代码要执行之后,接下来的事情将被从作业队列中推送到我们的调用堆栈。
事件循环 (Event Loop)
It’s time we put everything together that we have learnt above and understand the complete concurrency model of JavaScript.
现在是时候将上面学到的所有内容放在一起,并理解JavaScript的完整并发模型了。
The Event Loop monitors the Callback Queue and Job Queue and decides what needs to be pushed to the Call Stack.
事件循环监视回调队列和作业队列,并确定需要推送到调用堆栈的内容。
Basically following are few simple rules, which decides what needs to be pushed to the Call Stack and in what order —
基本上,下面是一些简单的规则,这些规则决定了哪些内容需要按什么顺序推送到调用堆栈中,
When the JavaScript file first loads in the browser, global context gets pushed to the Call Stack, i.e., the main function of JavaScript gets executed.
当JavaScript文件首次加载到浏览器中时, 全局上下文将被推送到调用堆栈 ,即,JavaScript的主要功能将被执行。
In order, synchronous code gets executed and any synchronous function is pushed to the Call Stack, in order it is found.
按顺序执行同步代码,并将所有同步功能按顺序发送到调用堆栈 。
Whenever an async task is performed using WebAPIs, a callback associated with that task gets pushed to the Task Queue when the async task gets completed.
每当使用WebAPI执行异步任务时,与异步任务关联的回调都会在异步任务完成时被推送到任务队列。
Whenever an async task is performed using Promise, the callback associated with Promise is pushed to the Job Queue when Promise gets resolved!
每当使用Promise执行异步任务时,与Promise关联的回调都会在Promise得到解决时被推送到作业队列中!
If we have a current execution context present in Call Stack and no more sync code is left to be executed, the next function is taken from Job Queue, if Job Queue is not empty.
如果调用堆栈中存在当前执行上下文,并且没有其他同步代码要执行,那么如果Job Queue不为空,则从Job Queue中获取下一个函数。
If we have a current execution context present in Call Stack and no more sync code is left to be executed, the next function is taken from Task Queue, if Job Queue is empty.
如果调用栈中存在当前执行上下文,并且没有其他同步代码要执行, 则如果作业队列为空,则从任务队列中获取下一个功能。
Let’s look at the following example and its Call Stack diagram to conclude whatever we have learned so far —
让我们看下面的示例及其调用堆栈图,以总结到目前为止所学的内容-
![Image for post](https://miro.medium.com/max/9999/1*jf9ZjoLt0vTuP1RUtfIXzg.png)
swoole 调用异步队列