JavaScript 异步
JavaScript 为什么需要异步
- JavaScript是一门单线程的语言,运行在浏览器中,
- 如果JavaScript所有操作都为同步,当执行一些比较耗时的操作时,浏览器页面就会卡顿,
- 为了优化用户体验,针对这种场景,JavaScript被设计为可以进行异步操作。
说一下异步是如何实现的
- 一切的异步都是对回调函数的封装,
- 在ES6以前的时代,实现异步是通过回调函数实现的,
- 在ES6中,引入了社区产物Promise,通过.then()和.catch()实现异步;同时也可以使用Generator函数进行异步操作,
- 在ES7中,引入了Promise的语法糖 async/await。
为什么会引入 Promise
- Promise本质是实现了回调函数的封装,这是为了解决“回调地狱”的问题,
- 当多层回调函数嵌套时,代码可读性会严重降低,同时多层callback的结构也会难以维护,这种情况就是“回调地狱”,
- 如果使用了Promise,即使需要多层的异步操作,也可以用链式写法,这样的代码更利于人理解,更利于后期的维护。
如何使用 Generator 处理异步操作
- 定义Generator函数时,需要使用
function* xxx(){}
,
- 当调用Generator函数时,该函数不会立即执行,而是会返回一个可迭代的对象,
- 当调用了返回可迭代对象中的
next()
方法时,会执行之前的函数中的代码,直到遇到 yield 关键字时,再次暂停,
- 调用
next()
方法会返回一个对象,包含value属性和done属性,value 是遇到 yield 关键字之前返回的值,而done 属性是当前迭代器是否执行完毕。
浏览器中的微任务
- process.nextTick
- Promise
- Async/Await(实际就是promise)
- MutationObserver(html5新特性)
浏览器中的宏任务
- setTimeout
- setInterval
- setImmediate
- I/O
说一下事件轮询机制
- 首先会一行一行地将同步代码放入调用栈中执行,
- 如果遇到了异步代码,会等待时机,
- 如果时机已到,异步代码为宏任务时会放入宏任务队列中等待执行,微任务会放入微任务队列中等待执行,
- 当同步代码执行完毕时,会先执行微任务队列中的微任务,调用顺序为先进入队列先调用,
- 微任务队列清空时,如果DOM结构改变,会尝试DOM结构的渲染,
- 执行宏任务队列的宏任务,
- 当宏任务产生了新的微任务时,在执行完当前宏任务时会优先清空微任务队列,
- 循环4-7这个过程。