浏览器内核的多线程
js引擎
Gui线程
浏览器事件触发线程
事件循环机制
任务队列中分为 macro-task(宏任务)与micro-task(微任务)
-
macro-task大概包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
浏览器发起宏任务
-
micro-task【先执行】大概包括: process.nextTick, Promise, Object.observe(已废弃), MutationObserver(html5新特性)
JS引擎发起微任务
setTimeout/Promise等我们称之为任务源。而进入任务队列的是他们指定的具体执行任务。
事件循环的顺序,决定了JavaScript代码的执行顺序。它从script(整体代码)开始第一次循环。之后全局上下文进入函数调用栈。直到调用栈清空(只剩全局),然后执行所有的micro-task。当所有可执行的micro-task执行完毕之后。循环再次从macro-task开始,找到其中一个任务队列执行完毕,然后再执行所有的macro-task,这样一直循环下去。所以微任务会先执行,宏任务后执行,先promise()再setTimeout()
回调函数(setTimout使用的就是回调函数)
它是属于任务队列中的宏任务
缺点:- 回调地狱
- 不能捕获异常
Promise函数
它是属于任务队列中的微任务
返回一个承诺对象,它会在某个特定的时刻执行,两个参数resolve()和reject()代表成功和失败;我们在需要执行异步的地方直接使用then()即可;优点:
- 它将执行代码和处理逻辑的代码清晰的分离了
缺点:
- 书写不太方便,还是存在一定的回调感觉(.then().then())
async和awit函数
它是属于任务队列中的微任务
async 函数必定返回 Promise,我们把所有返回 Promise 的函数都可以认为是异步函数。 async 函数是一种特殊语法,特征是在 function 关键字之前加上 async 关键字,这样, 就定义了一个 async 函数,我们可以在其中使用 await 来等待一个 Promise。
优点:- 书写规范,允许嵌套,最优的异步实现方案
缺点:
- 兼容问题
Generator 函数
状态机,内部封装了多个状态
- 回调地狱
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';}
// 它返回的是一个指向内部状态的对象,一个遍历器对象
var hw = helloWorldGenerator();
// 调用next()方法,使得指针移动向下一个,value为内部状态的值。done表示遍历是否结束
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }