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

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

如何模拟一个微任务

微任务

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

小结

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

相关推荐
神奇的程序员4 小时前
开发了一个管理本地开发环境的软件
前端·flutter
天若有情6734 小时前
程序员原创|借鉴JS事件冒泡,根治电脑文件混乱的“冒泡整理法”
开发语言·javascript·windows·ecmascript·电脑·办公·日常
XiYang-DING5 小时前
HTML 核心标签
前端·html
Csvn5 小时前
技术选型方法论
前端
Csvn5 小时前
前端架构演进:从页面到平台的十年变革
前端
李伟_Li慢慢5 小时前
ShaderToy-山峦+蓝天+白云
前端·webgl
小码哥_常6 小时前
Android字体字重设置全攻略:XML黑科技+Kotlin动态实现,告别.ttf臃肿
前端
FYKJ_20106 小时前
springboot校园兼职平台--附源码02041
java·javascript·spring boot·python·eclipse·django·php
AI人工智能+电脑小能手7 小时前
【大白话说Java面试题】【Java基础篇】第30题:JDK动态代理和CGLIB动态代理有什么区别
java·开发语言·后端·面试·代理模式
言萧凡_CookieBoty7 小时前
AI 编程省 Token 实战:从 Spec、上下文工程到模型分层的降本策略
前端·ai编程