同步和异步| 青训营笔记

81 阅读2分钟

这是我参与「第四届青训营 」笔记创作活动的第4天

同步与异步

1. 同步

JS 是单线程的,代码至上而下执行时遇到同步的代码需要先执行完才可以进行下一步任务。比如循环等\

2. 异步

所有需要等待的任务都是异步的。遇到异步代码时,不需要等待而是直接异步任务放入任务队列,等到后面的任务完成后,才会返回来执行没有完成异步的代码。比如事件绑定,所有定时器,ajax 的异步处理,部分回调函数,浏览器的渲染过程等等。\

let a = 0
setTimeout(() =>{
    console.log('a', ++a)
}, 0)
console.log(a)
while(true){
}

上面的代码死循环了,即使定时器的时间到了也不会执行。因为同步的代码没有执行完一步就不会执行。

  • ❓为什么script标签要放在body的下面,而link引用css要放在body的上面?

    • 当浏览器解析HTML的时候,当读到<link rel=”stylesheet” href=”index.css” />浏览器会一边加载css,一边继续读HTML构建dom树(异步加载)。
    • 而当读到< script type=”text/javascript” src=”zhiruo.js”></script>时,浏览器会停止解析,等待js脚本加载完毕之后,才会继续构建dom树(同步加载)
    • 所以,如果将script标签放在最上面,会阻塞后续的进程。
  • ❓为什么script标签是同步加载,而css引用是异步加载呢

    因为js脚本中有大量对dom树中结点的操作(增删查改),如果两者异步操作,则会存在进程冲突(可能dom已经解析完了,脚本又对其进行删改,也可能dom还没有解析到,但脚本就开始用getElementById进行获取该节点),导致进程被阻塞。所以应该先加载HTML构建dom树,再加载js脚本,减少阻塞。

  • ❓script标签中加入defer=”defer” 有什么效果

    IE8及其以下都支持

    加入defer=”defer”后,该进程会异步加载js脚本文件,但加载完之后并不立即执行(如果脚本里面有console.log(1),并不是加载完后立即输出),而是在DOM树解析完毕之后才开始执行。

  • ❓script标签中加入async=”async” 有什么效果

    IE9及其以上支持

    和defer几乎一样,也是异步加载,但只要自己一加载完就立即执行,不会等到DOM树解析完毕后才执行

⇒ 当defer和async都添加到script标签中后,浏览器只认async。

⇒ 如果你要将js脚本异步加载,在该脚本中不要对文档进行操作。