JS 会建立一个相似于 while (true) 的循环,每执行一次循环体的过程称之为 Tick。每次 Tick 的过程就是查看是否有待处理事件,若是有则取出相关事件及回调函数放入执行栈中由主线程执行。待处理的事件会存储在一个任务队列中,也就是每次 Tick 会查看任务队列中是否有须要执行的任务。javascript
异步操做会将相关回调添加到任务队列中。而不一样的异步操做添加到任务队列的时机也不一样,如 onclick, setTimeout, ajax 处理的方式都不一样,这些异步操做是由浏览器内核的 webcore 来执行的,webcore 包含上图中的3种 webAPI,分别是 DOM Binding、network、timer模块。java
1. onclick 由浏览器内核的 DOM Binding 模块来处理,当事件触发的时候,回调函数会当即添加到任务队列中。node
2. setTimeout 会由浏览器内核的 timer 模块来进行延时处理,当时间到达的时候,才会将回调函数添加到任务队列中。web
3. ajax 则会由浏览器内核的 network 模块来处理,在网络请求完成返回以后,才将回调添加到任务队列中。面试
任务队列是在事件循环之上的,事件循环每次 tick 后会查看 ES6 的任务队列中是否有任务要执行,也就是 ES6 的任务队列比事件循环中的任务(事件)队列优先级更高。如 Promise 就使用了 ES6 的任务队列特性。ajax
浏览器的内核是多线程的,它们在内核控制下相互配合以保持同步,一个浏览器至少实现三个常驻线程:JavaScript引擎线程,GUI渲染线程,浏览器事件触发线程。数据库
优势:一、将耗时较长的操做(网络请求、图片下载、音频下载、数据库访问等)放在子线程中执行,能够防止主线程的卡死;二、能够发挥多核处理的优点,提高cpu的使用率。 缺点:一、每开辟一个子线程就消耗必定的资源; 二、会形成代码的可读性变差;三、若是出现多个线程同时访问一个资源,会出现资源争夺的状况。promise
async function async1(){
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start')
setTimeout(function(){
console.log('setTimeout')
},0)
async1();
new Promise(function(resolve){
console.log('promise1')
resolve();
}).then(function(){
console.log('promise2')
})
console.log('script end')
/* 解题思路: 首先按照代码的执行顺序从上往下,js始终都是单线程的,先执行的确定是同步任务,再根据进入任务队列的顺序先进先出,先微后宏。 微任务是一次性将队列中存在的微任务执行完毕,宏任务是一个一个先进先出。 Promise是一个构造函数,调用的时候会生成Promise实例。当Promise的状态改变时会调用then函数中定义的回调函数。 咱们都知道这个回调函数不会马上执行,他是一个微任务会被添加到当前任务队列中的末尾,在下一轮任务开始执行以前执行。 async/await成对出现,async标记的函数会返回一个Promise对象,可使用then方法添加回调函数。await后面的语句会同步执行。但 await 下面的语句会被当成微任务添加到当前任务队列的末尾异步执行。 */
/* 答案: > node8版本: script start -> async1 start -> async2 -> promise1 -> script end -> promise2 -> async1 end -> setTimeout <= node8版本: script start -> async1 start -> async2 -> promise1 -> script end -> async1 end -> promise2 -> setTimeout 这主要是node.js8版本与其余版本的差别,他们对await的执行方法不一样 */
复制代码