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

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

如何模拟一个微任务

微任务

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

小结

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

相关推荐
悟忧19 小时前
规避ProseMirror React渲染差异带来的BUG
前端
小皮虾19 小时前
小程序云开发有类似 uniCloud 云对象的方案吗?有的兄弟,有的!
前端·javascript·小程序·云开发
Android疑难杂症19 小时前
鸿蒙Notification Kit通知服务开发快速指南
android·前端·harmonyos
T___T19 小时前
全方位解释 JavaScript 执行机制(从底层到实战)
前端·面试
阳懿19 小时前
meta-llama-3-8B下载失败解决。
前端·javascript·html
Qinana19 小时前
🌊 深入理解 CSS:从选择器到层叠的艺术
前端·css·程序员
IT_陈寒19 小时前
Python 3.12新特性实测:10个让你的代码提速30%的隐藏技巧 🚀
前端·人工智能·后端
史林枫19 小时前
JavaScript 中call和apply的详细讲解 —— 连10岁的小朋友都能看懂!
javascript·apply·call
闲人编程19 小时前
从零开发一个简单的Web爬虫(使用Requests和BeautifulSoup)
前端·爬虫·beautifulsoup·bs4·web·request·codecapsule
9号达人19 小时前
普通公司对账系统的现实困境与解决方案
java·后端·面试