一:eventloop
这时候,await会阻塞async的返回值,先跳出async1进行往下执行同步任务。
当async外面的同步任务都执行完成了,因此就重新回到前面阻塞的位置,进行往下执行。
事件循环的具体流程如下:
- 从宏任务队列中,按照入队顺序,找到第一个执行的宏任务,放入调用栈,开始执行;
- 执行完该宏任务下所有同步任务后,即调用栈清空后,该宏任务被推出宏任务队列,然后微任务队列开始按照入队顺序,依次执行其中的微任务,直至微任务队列清空为止;
- 当微任务队列清空后,一个事件循环结束;
- 接着从宏任务队列中,找到下一个执行的宏任务,开始第二个事件循环,直至宏任务队列清空为止。
这里有几个重点:
- 当我们第一次执行的时候,解释器会将整体代码script放入宏任务队列中,因此事件循环是从第一个宏任务开始的;
- 如果在执行微任务的过程中,产生新的微任务添加到微任务队列中,也需要一起清空;微任务队列没清空之前,是不会执行下一个宏任务的
页面渲染
每次当一次事件循环结束后,即一个宏任务执行完成后以及微任务队列被清空后 (如果有执行到dom操作的话),浏览器就会进行一次页面更新渲染。
通常我们浏览器页面刷新频率是60fps,也就是意味着120ms要刷新一次,因此我们也要尽量保证一次事件循环控制在120ms之内,这也是我们需要做代码性能优化的一个原因。
二: ast 语法树
1,字节流转换过程
字节流(源数据) ==> 字符串 =======》 tokens标记 ==》 node节点 ====》dom树
2,转换过程
demo
那变成tokens后,如下:
tagName: html |type: DOCTYPE |attr: |text: " tagName: |type: Character |attr: |text: \n" tagName: html |type: startTag |attr: |text: " tagName: |type: Character |attr: |text: \n" tagName: head |type: startTag |attr: |text: " tagName: |type: Character |attr: |text: \n "
事实上,构建DOM的过程中,不是等所有Token都转换完成后再去生成节点对象,而是一边生成Token一边消耗Token来生成节点对象,!
3.注意事项
HTML和CSS都是渲染阻塞资源
在构建DOM的过程中,如果遇到link的标签,当把它插到DOM里面之后,就会触发资源加载,不会影响DOM树的构建,只是说在CSS没处理好之前,构建好的DOM并不会显示出来(渲染时中断)
在构建DOM时,HTML解析器若遇到了JavaScript,那么它会暂停构建DOM,将控制权移交给JavaScript引擎,等JavaScript引擎运行完毕,浏览器再从中断的地方恢复DOM构建(Dom构建时中断)
如果有CSS正在处理中,这时候又来了JS,那DOM暂停(要等JS),JS也不会执行(要等CSSOM)。等CSS处理完后,JS再执行,等JS执行完后,DOM再继续。
JS的执行要等待位于其前面的CSS和JS加载、执行完。
JavaScript 想访问 CSSOM 并更改它 。浏览器会先去构建 CSSOM,然后再执行 JavaScript,最后在继续构建 DOM。