Java Script 最大的特点就是它是 单线程,单线程的意思就是在同一间时间只能做一件事,例如在一个DOM 中,增删元素,我们只能先增加再删除,不能同时进行。单线程就意味着所有的任务都需要排队,前一个任务结束,才能执行下一个任务,这就可能导致如果代码过长的话 页面渲染不连贯,渲染加载阻塞等。
为了解决这个问题,HTML5 提出来了webworker 标准,允许 Java Script 创建多个线程,于是出现了 同步 与 异步
同步:
按顺序执行代码,前一个任务结束再执行下一个任务,程序执行顺序和代码编写顺序一致。
异步:
做一件事需要花费很长时间的话,可以先处理别的事情,例如我们做饭,在烧水时就可以去切菜,不需要等水烧开了再去切菜。
例如在这个代码中:
<script>
window.setTimeout(function(){
console.log(1);
},2000)
console.log(2);
</script>
按照正常的 同步思想,我们肯定会认为先输出1,再顺序输出2,但其实结果为先输出2,再输出1,这是因为在顺序执行代码时,遇到了定时器,等待时间比较长,所以先执行了后面的代码,最后再执行定时器回调函数里的代码,大大提高了程序的执行效率。
同步与异步的任务执行过程:
同步任务:同步任务都放在了主线程上执行,形成了一个主线程执行栈
异步任务:异步任务通常通过回调函数来实现,异步任务通常有以下几种类型:click,mouseover,focus 等等,以及定时器 setTimeout,setInterval 等等,异步任务会将其相关回调函数加入到任务队列中(或称为消息队列)
所以刚才的案例就可以简单理解为下图,代码首先同步执行,在遇到了回调函数后,将回调函数放入了任务队列中,然后跳过该任务先执行下面的代码,等待主线程执行栈同步任务全部执行完后,再去任务队列中找未执行的回调函数去执行,可以将此抽象为主线程执行栈为主车道,任务队列为应急车道,回调函数就是半路坏掉的汽车,需要离开主车道不影响正常通行,到任务队列修车等待,待主车道车全部离开后,再由应急车道驶向主干道
有多个回调函数的任务执行过程:
如果有多个回调函数,那么任务队列中先执行哪个回调函数就成了问题,这时候就需要 ----- 异步进程处理
<script>
document.addEventListener('click',function(){
console.log(1);
})
window.setTimeout(function(){
console.log(2);
},2000)
</script>
例如此代码,我们程序是如何执行的呢,其实在将回调函数传入任务队列前,还经过了一个异步进程处理,只有触发了才会放入任务队列中,例如第一个点击事件,只有点击了,才会将其回调函数放入任务队列中,不点击不放入。又如第二个定时器,两秒过去了才会将其回调函数放入任务队列中
对于主线程结束后不断地去任务列表中获取新的回调函数任务,再去执行,再去获取,再去执行,这个阶段称为 事件循环 event loop