javascript并发_JavaScript并发模型和事件循环

javascript并发

Javascript runtime is single threaded which means that it can execute one piece of code at a time. In order to understand the concurrency model and the event loop in Javascript we have to first get to know some common terms that are associated with it.

Javascript运行时是单线程的,这意味着它可以一次执行一段代码。 为了理解Java中的并发模型和事件循环,我们必须首先了解一些与之关联的通用术语。

调用栈 (The call stack)

First let’s learn about what a call stack is.

首先,让我们了解什么是调用堆栈。

A call stack is a simple data structure that records where in the code we are currently. So if we step into a function that is a function invocation it is pushed to the call stack. When we return from a function it is popped out of the stack.

调用栈是一个简单的数据结构,记录了我们当前在代码中的位置。 因此,如果我们进入作为函数调用的函数,它将被推送到调用堆栈。 当我们从函数返回时,它会弹出堆栈。

Let’s look at a code example to understand the call stack:

让我们看一个代码示例,以了解调用堆栈:

function multiply(x,y) {
   return x * y;
}

function squared(n) {
     return multiply(n,n)
  }

function printSquare(n) {
   return squared(n)
}

let numberSquared = printSquare(5);
console.log(numberSquared);

First when the code executes the runtime will read through each of the function definitions. But when it reaches the line where the first function printSquare(5) is invoked it will push this function into the call stack.

首先,当代码执行时,运行时将通读每个函数定义。 但是,当到达调用第一个函数printSquare(5)的行时 ,它将把该函数推入调用堆栈。

Next, this function will execute. Before returning it will encounter another function, squared(n), so it will suspend its current operation and push this function on top of the existing function.

接下来,将执行此功能。 在返回之前,它将遇到另一个函数squared(n)因此它将暂停其当前操作并将该函数推入现有函数的顶部。

It executes the function (in this case the squared function) and finally it encounters another function multiply(n,n). Then it suspends its current executions and pushes this function into the call stack. The function multiply executes and it returns with the multiplied value.

它执行函数(在这种情况下为平方函数),最后遇到另一个函数multiple(n,n) 然后,它挂起其当前执行,并将此函数推入调用堆栈。 该函数执行乘法,并返回相乘后的值。

Finally the squared function returns and is popped off the stack and then the same goes with printSquare. The final squared value is allocated to the numberSquared variable.

最后,平方函数返回并从堆栈中弹出,然后printSquare也是如此。 最终的平方值分配给numberSquared变量。

We encounter again a function invocation (in this case it’s a console.log() statement) so the runtime pushes this to the stack. This executes it thus printing the squared number on the console.

我们再次遇到函数调用(在本例中为console.log()语句),因此运行时将其推入堆栈。 这样执行它,从而在控制台上打印平方数。

Note that the first function that gets pushed into the stack before any of the above code runs is the main function. In the runtime this is denoted as an ‘anonymous function’.

请注意,在上述任何代码运行之前,第一个被压入堆栈的函数是main函数。 在运行时,这被称为“匿名函数”。

So to summarize: whenever a function is invoked it is pushed into the call stack where it executes. Finally when the function is done with its execution and is returning either implicitly or explicitly it will be popped off the stack.

总结一下:每当调用一个函数时,它将被推入执行该函数的调用堆栈中。 最后,当函数执行完毕并隐式或显式返回时,它将从堆栈中弹出。

The call stack just records at what point in time which function was executing. And it keeps track of which function is currently executing.

调用堆栈仅记录哪个函数在什么时间执行。 并且跟踪当前正在执行哪个功能。

浏览器 (The browser)

Now we know from this that Javascript can execute one thing at a time but that’s not the case with the Browser. The Browser has its own set of APIs like setTimeout and XMLHttpRequests which are not specified in the Javascript runtime.

现在我们从中知道Javascript一次可以执行一件事,但浏览器不是这种情况。 浏览器有自己的API集,例如setTimeout和XMLHttpRequests,它们在Javascript运行时中未指定。

In fact if you look through the source code of V8, the popular Javascript runtime that powers browsers like Google Chrome, you won’t find any definitions for it. That's because these special web API’s exist in the browser environment not inside the javascript environment. So you can say that these APIs introduce concurrency into the mix.

实际上,如果您浏览V8的源代码,V8是为Google Chrome之类的浏览器提供支持的流行Javascript运行时,则不会找到任何定义。 这是因为这些特殊的Web API存在于浏览器环境中,而不存在于javascript环境中。 因此,可以说这些API将并发引入了混合。

Let’s look at a diagram to understand the whole picture.

让我们看一个图表以了解整个图片。

Some more terms are introduced here, so let's go through them:

这里介绍了更多的术语,让我们仔细研究一下:

Heap: It’s mostly the place where objects are allocated.

通常是分配对象的地方。

Callback Queue: It’s a data structure that stores all the callbacks. Since it’s a queue, the elements are processed based on FIFO which is First in First Out.

回调队列这是一个存储所有回调的数据结构。 由于是队列,因此将根据先进先出的FIFO处理元素。

Event Loop: This is where all these things come together. The event loop simply checks the call stack, and if it is empty (which means there are no functions in the stack) it takes the oldest callback from the callback queue and pushes it into the call stack which eventually executes the callback.

事件循环所有这些东西都聚集在这里。 事件循环只是检查调用堆栈,如果它为空(这意味着堆栈中没有函数),它将从回调队列中获取最早的回调,并将其推入调用堆栈中,最终执行该回调。

Let’s understand this with a code example:

让我们通过一个代码示例来理解这一点:

console.log('hi');

setTimeout(function() {
     console.log('freecodeCamp')
},5000);

console.log('JS')

When the first line executes it’s a console.log(). This is a function invocation which means that this function is pushed into the call stack where it executes printing ‘hi’ to the console. Finally it’s returned and is popped off the stack.

第一行执行时为console.log()。 这是一个函数调用,这意味着该函数被推入调用堆栈中,在该堆栈中执行向控制台打印“ hi”。 最后,它被返回并从堆栈中弹出。

Then when the runtime goes to execute setTimeout() it knows that this is a web API. Therefore it gives it off to the browser to handle its execution. The browser starts the timer and then JS runtime pops the setTimeout() out of the stack. It encounters another console.log() invocation and so it pushes this into the call stack, the message ‘JS’ is logged into the console, and then it’s finally returned. Then the last console.log() is popped off the stack. Now the call stack is empty.

然后,当运行时执行setTimeout()时,它将知道这是一个Web API。 因此,它将它交给浏览器以处理其执行。 浏览器启动计时器,然后JS运行时将setTimeout()弹出堆栈。 它遇到另一个console.log()调用,因此将其推入调用堆栈,消息“ JS”被登录到控制台,然后最终返回。 然后,最后一个console.log()从堆栈中弹出。 现在,调用堆栈为空。

Meanwhile while all of this was going on the timer finishes. When 5 seconds have elapsed the browser goes ahead and pushes the callback function into the callback queue.

同时,在所有这些过程中,计时器完成。 5秒钟后,浏览器继续运行,并将回调函数推送到回调队列中。

Next the event loop checks if the call stack is free or not. Since it is free it takes the callback function and pushes it again back to the call stack which executes the code inside it.

接下来,事件循环检查调用堆栈是否空闲。 由于它是免费的,因此它将使用回调函数,并将其再次推回到执行其内部代码的调用堆栈。

Again inside the code there is a console.log() invocation so this function goes to the top of the stack executes which logs ‘freecodecamp’ into the console and finally it returns. This means it gets popped off the stack and finally the callback gets popped off the stack and we are done.

在代码中再次有一个console.log()调用,因此此函数到达执行堆栈的顶部,该代码将“ freecodecamp”记录到控制台中,最后返回。 这意味着它被弹出堆栈,最后回调被弹出堆栈,我们完成了。

To visualize this better try this tool by Phillip Roberts: Loupe Event Loop Visualizer

为了更好地可视化此效果,请尝试使用Phillip Roberts的以下工具: Loupe Event Loop Visualizer

翻译自: https://www.freecodecamp.org/news/javascript-concurrency-model-and-event-loop/

javascript并发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值