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

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

如何模拟一个微任务

微任务

首先简单了解一下什么是微任务?先谈宏任务,即不同类型的消息队列里的任务。微任务相对于宏任务,每个宏任务都关联一个微任务队列,在宏任务即将结束前都会清空微任务队列,执行微任务产生的新的微任务依然放在当前队列而不会延期到下一个宏任务。两者相辅相成,微任务的设计主要是在执行效率和时机上做一个权衡,在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. 借助原型链原理

典型的就是instanceof与 constructor

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

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

很明显,object是对象,但object instanceof Array 与object.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

小结

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

相关推荐
怕浪猫3 小时前
RAG 面试 6 连问,从原理到优化全部覆盖
python·算法·面试
To_OC4 小时前
从一头雾水到跑通全流程:我用一个周末啃透了JWT登录鉴权
前端·后端·http
excel6 小时前
研究 Vue 3 源码的收获
前端·vue.js
可乐鸡翅yeah_8 小时前
业务中 M3U8 水印相关坑,硬水印和动态水印区别
前端·网络·数据库·ffmpeg·m3u8在线
lerhxx8 小时前
AI 应用如何高效优雅地恢复中断?—— "连接解耦 + 状态持久化"
前端·javascript
计算机魔术师8 小时前
METR 演示 AI 智能体如何篡改 Inspect 评估记录以掩盖不当行为
前端
前端snow8 小时前
ai agent --- 异步处理之 Rabbit MQ
前端
念何架构之路9 小时前
zap扩展生态与总结
java·前端·数据库
独孤九剑打醒他9 小时前
【原创开源】【概念设计】源 - 栅 - 漏 - 栅 - 源 横向双栅 MOS,低压交流多值逻辑芯片探索
前端·其他·架构·开源·硬件工程
mantou1329 小时前
我给 AI Agent 做了个「油猴」:让 Claude Code / Codex 直接用你已登录的浏览器
前端·javascript·后端