javaScript是典型的单线程并发语言,表示在同一时间内只能执行单个任务或部分代码片,它的主要用途是与用户互动,以及操作DOM,这就决定了它只能是个单线程。即javaScript主线程拥有一个函数调用栈以及一个任务队列。主线程依次执行代码,遇到函数时,会先将函数入栈,函数运行完毕后再将函数出栈,直到所有代码执行完毕。当函数调用栈为空时,运行时根据事件循环(EventLoop)机制来从任务队列中取出待执行的回调并执行,执行过程中同样会进行函数帧的入栈出栈操作。
H5中的Web Worker标准虽然是多线程,但Web Worker和JS主线程不是平级的,主线程可以控制Web Worker,并且Web Worker不能操作DOM,不能访问document、window、parent。
JavaScript中的其它线程,定时触发线程,异步请求线程,处理DOM事件的线程,称之为工作线程。
Event Loop(事件循环)并不是 JavaScript 中独有的,其广泛应用于各个领域的异步编程实现中;所谓的 Event Loop 即是一系列回调函数的集合,在执行某个异步函数时,会将其回调压入队列中,JavaScript 引擎会在异步代码执行完毕后开始处理其关联的回调。
在 Web 浏览器中,任何时刻都有可能会有事件被触发,而仅有那些设置了回调的事件会将其相关的任务压入到任务队列中
任务队列是一个事件的队列,也可以理解成消息的队列。
所有同步任务都在主线程上执行,形成一个执行栈。
只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
浏览器中的事件循环机制阐述如下:
1.浏览器内核会在其它线程中执行异步操作,当操作完成后,将操作结果以及事先定义的回调函数放入 JavaScript 主线程的任务队列中。
2.JavaScript 主线程会在执行栈清空后,读取任务队列,读取到任务队列中的函数后,将该函数入栈,一直运行直到执行栈清空,再次去读取任务队列,不断循环。
3.当主线程阻塞时,任务队列仍然是能够被推入任务的。这也就是为什么当页面的 JavaScript 进程阻塞时,我们触发的点击等事件,会在进程恢复后依次执行。
JavaScript 内存模型的角度,我们可以将内存划分为调用栈(Call Stack)、堆(Heap)以及队列(Queue)等几个部分。