Event Loop

2019-12-19  本文已影响0人  nymlc

进程和线程

我们打开电脑可以边听歌边写代码,这就是多任务。但是多年前的电脑可是单核的,它其实是让各个任务交替运行,只是每个任务运行很短的时间就切换到下一个任务,这样子就好像并行。其实真正的多任务并行只能在多核CPU上。不过任务一般都远远多于核心,所以其实还是多任务交替执行
对于操作系统而言,一个任务就是一个进程。一个任务一般而言不会只干一件事,就像看电影,不可能先看完在听音吧,这么些子任务其实就是线程,它和多任务一样也是交替执行
举个栗子,我们打开浏览器一个页签就是创建了一个进程,然后这个进程里有渲染线程、JS引擎、http线程等等
可以把这俩当做单位,操作系统能够调度的单位。

程序是指令、数据以及其组织形式的描述,进程就是程序的实体,也是线程的容器

并发和并行

并行是指同时执行,这个无论是宏观还是微观,程序都是一起执行的
并发是指在一个时间段之内多个程序执行,这个还微观上是顺序执行的,宏观上是同时的

宏任务和微任务

  1. 宏任务(macrotask)也叫tasks,一些异步任务的回调会被放进这个队列等待后续被调用,包括:setTimeout、setInterval、setImmediate、I/O、requestAnimationFrame(浏览器)、UI rendering(浏览器)、MessageChannel、ajax、script(JS文件)、postMessage
  2. 微任务(microtask)也叫jobs,另外一些异步任务会掉会被放进这个队列,包括:Promise、Object.observe、MutationObserver、process.nextTick(Node)

执行栈

JS代码运行是在执行上下文里进行的。有三种情况:

栗子

其实这个浏览器里的可能还不是那么好理解,如下图所示:

console.log('script start');

setTimeout(function cb1() {
      console.log('setTimeout');
}, 0);

Promise.resolve().then(function cb2() {
      console.log('promise1');
}).then(function cb3() {
      console.log('promise2');
});

console.log('script end');

写了个小栗子,参见Jake Archibald 的Tasks, microtasks, queues and schedules

栈的容量是有限制的,一旦存放过多,是会爆栈的

Tasks和Jobs交替入栈,区别在于Tasks里的先入栈,且单个入栈,Jobs的在栈空了被全部执行

Jobs执行期间新加入的job也算本轮次

任务队列

其实执行栈的时候就说到这了
JS是单线程源于JS出现为了解决用户互动一些简单任务,多线程的话就有复杂的同步问题
不过单线程就意味着需要排队,所以任务队列应运而生,只要先不管IO、http之类的任务,等到它们有了结果再回过头来继续执行。
任务分俩种,同步任务异步任务同步任务就是主线程上顺序执行的任务,异步任务就是不进入主线程,而是进入任务队列的任务。它们都有相应的模块去处理(DOM Binding、network、timer),就像setTimeout由timer模块处理,到点之后就会把回调函数加入到任务队列
异步执行机制如下:

JS的异步本质上来看还是同步的

浏览器线程

浏览器通常有GUI渲染线程、JavaScript引擎线程、定时触发器线程、事件触发器线程、异步HTTP请求线程。以定时触发器线程为例,遇到setTimeout的话就会交给它来处理,到点就加到tasks队列

后语

其实到这已经明白了,它是宿主环境为了解决JS单线程运行不阻塞的一种机制。
不过上面所诉其实都是浏览器的表现,即热式一种机制,不同的宿主自然也不一定一样的

上一篇 下一篇

猜你喜欢

热点阅读