关于js执行机制,老早以前就一直想写篇文章作个总结,由于和js执行顺序的面试题碰到的特别多,每次碰到老是会去网上查,没有系统地总结,搞得每次碰到都是似懂非懂的感受,这篇文章就系统的总结一下js执行机制。es6
你们都知道js最大的特色就是单线程执行,这就是为何js简单易学的一个重要缘由,不须要考虑复杂的同步问题,可是单线程也会有一个问题,全部的任务在执行的过程当中都必须等待前一个任务执行完成才能执行,这样就会带来一个效率的问题,为了解决这个问题,js将任务分为两种:同步任务和异步任务,同步任务就是以前说后一个任务必须等待前一个任务执行完成才能执行,是在主线程上执行的,而异步任务不会直接进入主线程执行,而是进入任务队列,只有在任务队列通知异步任务能够执行时,才会被推入主线程执行。让咱们来看一个更加直观的流程图:面试
说到异步任务,最多见就是setTimeout和setInterval两兄弟了,setTimeout是延迟必定时间后执行,可是只执行一次,setInterval是每隔必定的时间执行一次,会执行屡次,可是有时候咱们会发现设置必定的延迟时间后,回调函数的执行时间会比咱们设置的时间要晚,这是为何呢?上面咱们说过,在任务执行的时候setTimeout这类异步任务的回调会被放到异步队列中等待执行,当延迟时间结束时,若是主线程的任务已经执行完了,也就是处在空闲状态时,就会将任务队列的回调推到主线程执行,可是当主线程的任务尚未执行完成时,就只能继续等待,来看一个例子:promise
let before = new Date() setTimeout(() => { console.log(new Date() - before) }, 1000) for (let i = 0; i < 300000; i++) { console.log('time delay') }
从上面的例子就能够看到:当咱们执行完setTimeout以后,马上执行20万次的循环,从执行结果能够看到,setTimeout回调函数中的时间远高于设置1000ms,这就是由于时间到了,可是主线程的任务尚未执行完成致使。这种问题在setInterval设置倒计时的常常遇到,倒计时开始的时候设置的时间是从服务器拿到的系统时间很准确,可是若是后面不按期像服务期请求系统时间进行校准的话,你可能会发现倒计时的误差愈来愈来大,这就是主线程执行的时间比设定的延迟时间长致使的。服务器
在js中,异步任务除了有setTimeout这类的异步任务,还有一类就是es6中很经常使用promise...then这类的异步任务,所以除了同步任务和异步任务,任务还能够更加细分为macrotask(宏任务)和microtask(微任务)
macrotask: 包括setTimeout、setInterval和执行栈
microtask: 包括Promise、process.nextTick
要想理解这两个概念,直接从一道简单的面试题入手,来看一个例子:异步
setTimeout(function() { console.log(1) }, 0); new Promise(function(resolve, reject) { console.log(2); resolve() }).then(function() { console.log(3) }); process.nextTick(function () { console.log(4) }) console.log(5)
思考一下上面例子的输出结果,咱们来仔细分析一下执行过程:函数
最后用一张图来总结一下:spa
这篇文章简单介绍了js执行机制,但愿看了以后,能够对你们认识js的执行机制会有所帮助。
若是有错误或不严谨的地方,欢迎批评指正,若是喜欢,欢迎点赞收藏线程