进程、线程
- 进程是系统分配的独立自由,是CPU资源分配的基本单位,由一个或多个线程组成
- 线程是进程的执行流,是CPU调度和分派的基本单位,同进程中多个线程间是共享该进程的资源的
浏览器内核
浏览器是多进程的,每个tab标签都代表一个独立的进程(有时也不一定,多个空白tab标签会合并成一个进程),浏览器内核属于浏览器多进程中的一种。
浏览器内核中有多个线程在工作
- GUI渲染线程(与js引擎互斥)
- JS引擎线程
- 事件触发线程:当事件符合触发条件被触发时,该线程会把对应的事件回调函数添加到任务队列的队尾,等待 JS 引擎处理。
- 定时器触发线程:开启定时器触发线程来计时并触发计时,计时完成后会被添加到任务队列中,等待 JS 引擎处理。
- http请求线程:http 请求的时候会开启一条请求线程。
请求完成有结果了之后,将请求的回调函数添加到任务队列中,等待 JS 引擎处理。
JS 调用栈
JS 调用栈是一种后进先出的数据结构。当函数被调用时,会被添加到栈中的顶部,执行完成之后就从栈顶部移出该函数,直到栈内被清空。
同步任务、异步任务
JavaScript 单线程中的任务分为同步任务和异步任务。
同步任务会在调用栈中按照顺序排队等待主线程执行,
异步任务则会在异步有了结果后将注册的回调函数添加到任务队列(消息队列)中等待主线程空闲的时候,也就是栈内被清空的时候,被读取到栈中等待主线程执行。
任务队列是先进先出的数据结构。
Event Loop
调用栈中的同步任务都执行完毕,栈内被清空了,
就代表主线程空闲了,
这个时候就会去任务队列中按照顺序读取一个任务放入到栈中执行。每次栈内被清空,都会去读取任务队列有没有任务,有就读取执行,一直循环读取-执行的操作,就形成了事件循环。
宏任务(macro-task)、微任务(micro-task)
除了广义的同步任务和异步任务,JavaScript 单线程中的任务可以细分为宏任务和微任务。
macro-task包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver。
console.log(1);
setTimeout(function() {
console.log(2);
})
var promise = new Promise(function(resolve, reject) {
console.log(3);
resolve();
})
promise.then(function() {
console.log(4);
})
console.log(5);
//1,3,5,4,2
start
promise2
setInterval
setTimeout1