完整高频题库仓库地址:https://github.com/hzfe/awesome-interview
完整高频题库阅读地址:https://febook.hzfe.org/
相关问题
- JavaScript 异步编程方案有哪些
- JavaScript 异步编程方案各有什么优缺点
回答关键点
阻塞
事件循环
回调函数
JavaScript 是一种同步的、阻塞的、单线程的语言,一次只能执行一个任务。但浏览器定义了非同步的 Web APIs,将回调函数插入到事件循环,实现异步任务的非阻塞执行。常见的异步方案有异步回调、定时器、发布/订阅模式、Promise、生成器 Generator、async/await 以及 Web Worker。
知识点深入
1. 异步回调
异步回调函数作为参数传递给在后台执行的其他函数。当后台运行的代码结束,就调用回调函数,通知工作已经完成。具体示例如下:
// 第一个参数是监听的事件类型,第二个就是事件发生时调用的回调函数。
btn.addEventListener("click", () => {
console.log("You clicked me!");
const pElem = document.createElement("p");
pElem.textContent = "hello, hzfe.";
document.body.appendChild(pElem);
});
异步回调是编写和处理 JavaScript 异步逻辑的最常用方式,也是最基础的异步模式。但是随着 JavaScript 的发展,异步回调的问题也不容忽视:
- 回调表达异步流程的方式是非线性的,非顺序的,理解成本较高。
- 回调会受到控制反转的影响。因为回调的控制权在第三方(如 Ajax),由第三方来调用回调函数,无法确定调用是否符合预期。
- 多层嵌套回调会产生回调地狱(callback hell)。
2. 定时器:setTimeout/setInterval/requestAnimationFrame
这三个都可以用异步方式运行代码。主要特征如下:
- setTimeout:经过任意时间后运行函数,递归 setTimeout 在 JavaScript 线程不阻塞情的况下可保证执行间隔相同。
- setInterval:允许重复执行一个函数,并设置时间间隔,不能保证执行间隔相同。
- requestAnimationFrame:以当前浏览器/系统的最佳帧速率重复且高效地运行函数的方法。一般用于处理动画效果。
setInterval 会按设定的时间间隔固定调用,其中 setInterval 里面的代码的执行时间也包含在内,所以实际间隔小于设定的时间间隔。而递归 setTimeout 是调用时才开始算时间,可以保证多次递归调用时的间隔相同。
如果当前 JavaScript 线程阻塞,轮到的 setInterval 无法执行,那么本次任务就会被丢弃。而 setTimeout 被阻塞后不会被丢弃,等到空闲时会继续执行,但无法保证执行间隔。
3. 发布/订阅模式(publish-subscribe pattern)
发布/订阅模式是一种对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到状态改变的通知。