百度一面:如何模拟微任务?如何判断数组?

闲来无事,小记一下前段时间面试遇到的一些问题。需要说明的是,这些问题并不是一开始直接提问的,而是由之前的提问引申出来的。比如第一问题是在事件循环 中引申出来的,第二个问题是在数据结构中引申出来的。

如何模拟一个微任务

微任务

首先简单了解一下什么是微任务?先谈宏任务,即不同类型的消息队列里的任务。微任务相对于宏任务,每个宏任务都关联一个微任务队列,在宏任务即将结束前都会清空微任务队列,执行微任务产生的新的微任务依然放在当前队列而不会延期到下一个宏任务。两者相辅相成,微任务的设计主要是在执行效率和时机上做一个权衡,在WebAPI中产生微任务的常见方式为:Promise与MutationObserver。

MutationObserver为什么被设计成微任务

使用Promise可以产生微任务众人皆知,那MutationObserver API为什么被设计成微任务呢?首先,微任务是异步的,可以解决同步频繁更新DOM带来的性能 问题。其次,微任务的执行时机在当前宏任务阶段,这样也保证了执行的实时性

从caniuse中可以看到,在PC端,MutationObserver的兼容性较Promise好,在移动端Promise的覆盖范围更高,毕竟使用率极高,几乎得到了所有现代浏览器的支持。

代码实现

了解产生微任务的方式后,我们可以简单实现一下

javascript 复制代码
function microtask(task) {
    if (typeof Promise === "function") {
        Promise.resolve().then(task)
    } 
    else if(typeof MutationObserver === "function") {
        const ob = new MutationObserver(task)
        const textNode = document.createTextNode("")
        ob.observe(textNode, {
            // 监听文本数据
            characterData: true
        })
        textNode.data = "1"
    } 
    // 兼容node环境
    else if(process && typeof process.nextTick === "function") {
        process.nextTick(task)
    } 
    else {
        // 最后降级到setTimeout,虽然它是一个宏任务
        setTimeout(task, 0)
    }
}

queueMicrotask

期间被问到除了Promise和MutationObserver还有其它方式吗。详情参考MDN

判断数组及其优缺点

1. 使用toString

只要是涉及到判断数据类型,该方法是一定要提及的,否则你的技术形象在面试官眼里可能会瞬间崩塌。

css 复制代码
Object.prototype.toString.call([]) === '[object Array]'

依稀记得之前在看准网看过一篇面经,不知道是不是段子,现在还是可以找到的:

回归正题,这是es6之前比较通用的方法,但在es6之后就不再那么适用了,因为我们可以篡改toString的结果:

javascript 复制代码
Array.prototype[Symbol.toStringTag] = "篡改数组toString的结果";
Object.prototype.toString.call([]);
// '[object 篡改数组toString的结果]'

const obj = {
  [Symbol.toStringTag]: "篡改对象toString的结果"
};
Object.prototype.toString.call(obj);
// '[object 篡改对象toString的结果]'

2. 借助原型链原理

典型的就是instanceofconstructor

ini 复制代码
[] instanceof Array; // true
[].constructor === Array; // true

但这种方法也是有问题,比如篡改原型,举个例子: const object = { __proto__: Array.prototype } ,

很明显,object是对象,但object instanceof Arrayobject.constructor === Array的结果都是true。

再比如跨领域对象问题,当前页面的Array与iframe下的Array不同:

ini 复制代码
const iframe = document.createElement("iframe");
document.body.appendChild(iframe);
const xArray = window.frames[window.frames.length - 1].Array;
const arr = new xArray(1, 2, 3);

arr instanceof Array; // false

可以看到arr是通过iframe环境下的Array构造出来的,但它不是当前页面全局环境的Array的实例。

3. Array.isArray

鉴于以上种种原因,es6新增了Array.isArray(target)来准确判断数组。

javascript 复制代码
Array.isArray([]); // true

Array.isArray(new Array); // true

Array.isArray({ constructor: Array }); // true

Array.isArray({ __proto__: Array.prototype }); // false

Array.prototype[Symbol.toStringTag] = "篡改数组toString的结果";
Array.isArray([]); // true

const iframe = document.createElement("iframe");
document.body.appendChild(iframe);
const xArray = window.frames[window.frames.length - 1].Array;
const arr = new xArray(1, 2, 3);
Array.isArray(arr); // true

小结

其实,看似简单的问题也能触及到你的知识盲点。

相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
uhakadotcom9 小时前
视频直播与视频点播:基础知识与应用场景
后端·面试·架构
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom11 小时前
快速开始使用 n8n
后端·面试·github
uhakadotcom11 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github