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

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

如何模拟一个微任务

微任务

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

小结

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

相关推荐
GDAL34 分钟前
HTML 中的 Canvas 样式设置全解
javascript
m0_5287238140 分钟前
HTML中,title和h1标签的区别是什么?
前端·html
Dark_programmer40 分钟前
html - - - - - modal弹窗出现时,页面怎么能限制滚动
前端·html
GDAL1 小时前
HTML Canvas clip 深入全面讲解
前端·javascript·canvas
禾苗种树1 小时前
在 Vue 3 中使用 ECharts 制作多 Y 轴折线图时,若希望 **Y 轴颜色自动匹配折线颜色**且无需手动干预,可以通过以下步骤实现:
前端·vue.js·echarts
GISer_Jing1 小时前
Javascript排序算法(冒泡排序、快速排序、选择排序、堆排序、插入排序、希尔排序)详解
javascript·算法·排序算法
贵州数擎科技有限公司1 小时前
使用 Three.js 实现流光特效
前端·webgl
JustHappy1 小时前
「我们一起做组件库🌻」做个面包屑🥖,Vue的依赖注入实战💉(VersakitUI开发实录)
前端·javascript·github
拉不动的猪1 小时前
刷刷题16
前端·javascript·面试
kiramario1 小时前
【结束】JS如何不通过input的onInputFileChange使用本地mp4文件并播放,nextjs下放入public文件的视频用video标签无法打开
开发语言·javascript·音视频