【】渲染进程中有个主线程处理安排好的任务,为了在线程运行过程中接收并处理新任务,引入了事件循环机制
;为了处理其他线程发送来的任务,引入消息队列
;为了处理其他进程发送来的任务,渲染进程专门有一个IO线程来接收其他进程传进来的信息
【】通常我们把消息队列中的任务称为宏任务
,每个宏任务中都包含一个微任务队列
,在执行宏任务的过程中,如果DOM有变化,那么就会将该变化添加到微任务列表中。等宏任务中的主要功能都执行完成后,渲染引擎并不着急去执行下一个宏任务,而是执行当前宏任务中的微任务
【】通过 setTimeout
来介绍事件循环的应用。为了保证回调函数在指定时间内执行,不能将定时器的回调函数直接添加到消息队列中,在 chrome 中除了正常使用的消息队列外,还有另外一个消息队列,这个队列中维护了延迟执行的任务列表,包括定时器和内部一些其他的延迟执行的任务,所以当js创建一个定时器时,渲染进程会将该定时器的回调任务添加到延迟队列中。注意,延迟队列其实是hsahmap结构
【】在来看看 XMLHttpRequest
运行机制
【】现代浏览器里,产生微任务
有两种方式:第一种方式是使用 MutationObserver 监控某个 DOM 节点,然后再通过 JavaScript 来修改这个节点,或者为这个节点添加、删除部分子节点,当 DOM 节点发生变化时,就会产生 DOM 变化记录的微任务。第二种方式是使用 Promise,当调用 Promise.resolve() 或者 Promise.reject() 的时候,也会产生微任务。
【】先执行宏任务在执行微任务,在执行宏任务中会分同步任务和异步任务,先执行同步任务,异步任务又分宏任务和微任务,宏任务放到消息队列中,微任务全部执行完,在通过事件循环机制拿到下个宏任务。在渲染进程内会维护多个消息队列,每次事件循环机制会拿到最老的事件去执行,每次执行宏任务时都会创建对应的微任务
【】Promise 实例有三种状态:pending、fulfilled、rejected
,一旦状态改变,就不会再变。Promise.prototype上有三种方法:then()、catch()、finally()
。Promise实例创建后,执行器里的逻辑会立即执行。Promise还有很多方法:Promise.all()、Promise.race()、Promise.allSettled()、Promise.any()
。Promise本来是用于解决回调地狱的问题,借助.then
返回一个Promise,使用链式调用:
getData1().then(res=>{
console.log(res) // data1
return getData2();
}).then(res=>{
console.log(res) // data2
return getData3();
}).then(res=>{
console.log(res) // data3
})
【】生成器(Generator)是 ES6 提供的一种异步编程解决方案,主要原因是它可以在执行中被中断( yield )、然后等待一段时间再被我们唤醒( next() )。它的底层实现机制——协程,协程是一种比线程更加轻量级的存在
function* genDemo() {
console.log("开始执行第一段")
yield 'generator 2'
console.log("开始执行第二段")
yield 'generator 2'
console.log("开始执行第三段")
yield 'generator 2'
console.log("执行结束")
return 'generator 2'
}
console.log('main 0')
let gen = genDemo()
console.log(gen.next().value)
console.log('main 1')
console.log(gen.next().value)
console.log('main 2')
console.log(gen.next().value)
console.log('main 3')
console.log(gen.next().value)
console.log('main 4')
【】ES7 引入了 async/await,这是 JavaScript 异步编程的一个重大改进,提供了在不阻塞主线程的情况下使用同步代码实现异步访问资源的能力,并且使得代码逻辑更加清晰。async 函数是异步执行和隐式返回 Promise,await会默认创建一个 Promise 对象,而 await 后面的代码需要在它执行完后在执行
async function foo() {
console.log(1)
let a = await 100
console.log(a)
console.log(2)
}
console.log(0)
foo()
console.log(3)
参考资料:浏览器工作原理与实践