javascript的并发模型

javascript运行在单线程里,意思就是js每次只能执行一段代码。js有自己的并发模型,由栈、堆和队列组成。如下图

函数调用形成了一个栈帧,如下代码

function foo(b) {
	var a = 4;
	return a * b + 10;
}

function bar(x) {
	var y = 3;
	return foo(x * y);
}

console.log(bar(6));

依次调用函数进栈,等待函数返回后出栈,直到最后执行完毕按顺序出栈

在浏览器中函数执行抛出错误的时候也可以查看当前栈帧的情况

function foo () {
	throw new Error("error happen");
}
function bar () {
	foo();
}
function baz () {
	bar();
}
baz();

执行bar()后在控制台可以看到如下错误

给对象分配内存都在堆里实现的

队列

在js执行的过程中,所有的回调函数都会放到消息队列,当栈为空的时候,就从消息队列中取出函数逐一处理,直到栈为空时消息处理结束,例如 setTimeout 等函数

事件循环

不同于c++等多线程语言,js是单线程,所以需要事件循环来检测栈是否为空,然后把函数或者消息进栈执行,类似于这样实现

while (queue.waitForMessage()) {
    queue.processNextMessage();
}

浏览器的并发机制

浏览器提供了Web APIs,事件循环和回调队列,如下图


web APIs:包含ajax,setTimeout,Events等等
回调队列:所有的事件监听都会放到回调队列中去,例如点击,focus事件都放到此队列等待响应
事件循环:监听栈是否为空,然后把回调函数放到栈中执行

console.log(1);
setTimeout(function() {
    console.log(2)
}, 0);
console.log(3);

上面代码执行到setTimeout的时候回放到回调队列里面去,然后其他函数从上到下执行完毕,栈为空的时候就把回调函数放到栈中执行,所以结果输出为 1,3,2

参考资料

https://developer.mozilla.org/zh_cn/docs/Web/JavaScript/EventLoop

https://medium.com/@gaurav.pandvia/understanding-javascript-function-executions-tasks-event-loop-call-stack-more-part-1-5683dea1f5ec