面试高频题1

438 阅读47分钟

前言

本人也是大三到大四了,想在暑假找到一份工作。面了一些公司,汇总了一些面试常考题。因为答案都是基于个人来写所以可能并不是绝对正确,但是作者保证真的很用心去翻阅文档还有资料了。如果有错误欢迎评论区指正。我好好进行一个学习,谢谢大家了- ̗̀(๑ᵔ⌔ᵔ๑)

面试题

1-Node.js作为一种基于Chrome V8引擎的JavaScript运行环境,具有以下优势:

跨平台运行:Node.js能在多种操作系统上运行,如Windows、Linux和Mac OS X,便于开发跨平台应用程序。
单线程事件驱动架构:Node.js使用单线程事件驱动架构,能有效处理大量并发连接,适合构建实时应用,如即时聊天服务。
异步非阻塞I/O模型:这种模型允许Node.js在处理I/O操作时不会阻塞主线程,显著提高应用程序的性能和响应能力,尤其适用于处理高并发请求。
丰富的第三方模块:Node.js拥有庞大的第三方模块生态系统,便于开发者快速构建功能强大的应用程序。
简单易学的语法:基于JavaScript,其语法简单,易于上手,有利于快速开发。
广泛的社区支持:活跃的社区提供了丰富的资源和支持,便于解决问题和优化应用程序。
高性能和轻量级:Node.js在相对较低的硬件资源上即可运行,适用于云计算和分布式系统。
统一的语言开发:前后端均使用JavaScript,降低了开发成本,提高了开发效率。

2-项目发布的流程

测试:执行单元测试、集成测试和端到端测试,确保新的更改没有破坏现有功能。 ​ 打包:webpack,vite 进行一个项目的打包 ​ 预发布: ​ 在预发布环境中部署,模拟生产环境进行最后的测试。 ​ 可以进行A/B测试或金丝雀发布,逐步放量。 ​ 部署: ​ 使用持续集成/持续部署(CI/CD)工具(如Jenkins、GitLab CI/CD、Travis CI等)自动化部署流程。 ​ 部署到生产服务器,可以选择蓝绿部署、滚动更新等方式减少停机时间。

3-express和koa的区别

请记住,开发 Express 和 Koa 的是同一拨开发人员。Koa 只是 Express 的一个更轻量级的版本,

没有内置提供路由和模板引擎等功能。相比于 Koa,Express 更加成熟。

它的社区更为稳定,并且你可以在 Express 上找到比 Koa 更多的文档和示例。

虽然使用 Koa 可以使编写中间件更加简洁,但是使用 Express 结合 async/await 也可以避免“回调地狱”并实现类似的语法。

总之,就是 Express 和 Koa 能够实现完全一样的功能。从性能来说轻量级的Koa对于我的项目来说性能会更好。

中间件处理:

Express:Express使用传统的中间件模式,其中中间件函数按顺序执行,每个中间件可以控制请求的流程,例如是否调用next()

Koa:Koa引入了“洋葱模型”中间件,它允许中间件以更灵活的方式处理请求和响应,可以在流程的不同阶段插入逻辑。

上下文(Context):

Express:Express使用传统的req(请求)和res(响应)对象。

Koa:Koa引入了ctx(上下文)对象,它包含了reqres对象的封装,以及一些额外的功能。

异步处理:

Express:Express原生不支持异步中间件,通常需要使用回调或Promise来处理。

Koa:Koa内置了异步处理能力,它使用async/await语法,使得异步代码的编写更加直观和简洁。

4-node事件循环机制

这么通俗易懂的Node事件循环,背就完了 - 掘金 (juejin.cn)

5-vue2-vue3的区别

1. 语法区别
  • Vue 2

    • 主要使用选项式 API(Options API)。组件定义通过一个对象配置来完成,如 datamethodscomputedwatch 等属性都是在这个对象内定义的。
    • 代码组织较为分散,相关联的数据和逻辑可能分布在不同的选项中,这可能会导致代码维护困难。
  • Vue 3

    • 引入了组合式 API(Composition API),允许开发者在一个 setup() 函数中集中组织相关的状态和逻辑。
    • 组合式 API 使得代码更加模块化和可复用,可以更容易地抽取和共享逻辑。
    • 可以使用像 refreactivecomputedwatchEffectonMounted 这样的 Hooks 函数来替代 Vue 2 中的选项。
    • vue3是全部使用TS进行编写,更加符合大型项目
2. 响应式机制的改变
  • Vue 2

    • 使用 Object.defineProperty 来实现数据的响应式。当设置一个新属性时,需要手动调用 $set 方法。
    • 数组的变更检测存在局限性,例如直接修改数组的索引值或者添加/删除元素不会触发视图更新,需要使用特定的方法如 splice 或者 $setpush 等。
  • Vue 3

    • 使用 Proxy 对象来代替 Object.defineProperty,这提供了更全面的变更检测。
    • Proxy 可以拦截更多的操作类型,包括但不限于属性的读取、写入、删除等,因此对于数组的操作可以自动捕获到变更。
    • Vue 3 中的响应式对象还支持 readonlyshallowReactive 等新的选项,提供更多灵活性。
3. Diff 算法的改进
  • Vue 2

    • 使用一种简单的 diff 算法,主要基于两个假设:元素的唯一标识(key)和同级元素的顺序。
    • Vue 2 的 diff 算法相对简单,在复杂的应用场景下可能会导致不必要的重渲染。
  • Vue 3

    • 引入了更高效的 diff 算法,能够更好地处理复杂的 DOM 更新。
    • Vue 3 的 diff 算法更加智能,能够在不破坏性能的前提下做出更精细的更新决策。
    • Vue 3 的虚拟 DOM 实现也得到了优化,提高了渲染性能。
4.更加支持TypeScript
  • Vue 2

    • Vue 2 支持 TypeScript,但类型定义不是非常完善,使用 TypeScript 时可能遇到一些类型错误或警告。
  • Vue 3

    • Vue3 源码全面采用ts进行编写,组合式 API 的使用让 TypeScript 的类型推断变得更加容易,
    • 提高了开发效率和代码质量。
5.vue3有一个frament进行包裹

Vue2必须拥有一个根元素,而Vue3使用fragment进行了一个包裹,减少不必要的DOM层级:这有助于简化DOM结构,减少内存使用,提高渲染效率。

6&7-文件上传,断点续传具体实现&文件上传进度

一文搞懂前端文件上传操作 - 掘金 (juejin.cn)

字节跳动面试官:请你实现一个大文件上传和断点续传 - 掘金 (juejin.cn)

8-大文件怎么实现分片上传

1.首先要拿到大文件的二进制数据

2.使用数组对大文件进行slice分割

3.使用Promise.all并发请求发送给后台(要保证数据传输的时候要携带当前是第几片)

  1. 传输完成后通知服务器进行合并

9-选择器的优先级

important! > 行内样式 > id选择器 > 类选择器 > 标签选择器 > 通配符选择器 > 浏览器代理样式(标签默认样式)

div~span 选择的是和div同一层级下面的所有span元素(注意:和div同一层级不是子元素的意思) --- 兄弟选择器

div+span 选择的是相邻兄弟选择器,div最近的下一个span元素,不能是上面的。

10-浮动是什么?怎么清除浮动?

浮动就是让元素脱离文档流,向左或者向右浮动,直到遇到另一个浮动元素
清除浮动的方法
  1. 在浮动元素的最后面添加一个块级空容器,在它身上clear:both;
  2. 在父容器的伪元素上做清除浮动
  3. 父元素设置为BFC容器 什么是BFC容器呢?

BFC容器全名叫做Block Formatting Context

1-主要有两个作用

1.1- bfc容器在计算高度会计算浮动元素的高度

1.2- bfc容器子元素的margin-top不会与父容器的margin-top重叠

2- 设置bfc的方法

2.1 display:flex,gird,inline-block,inline-table,inline-flex

2.2 overflow:hidden,scroll,auto

2.3 position:absolute,fixed

2.4 float:left,right

11-防抖截流

1- 什么是防抖截流

防抖就是在一段时间内只会执行最后一次的操作

截流是触发一段时间内,每段固定时间执行一次

2-原理和作用

防抖和截流都是使用了定时器进行一个计时

防抖就是判断是否计时器存在,存在就清除重新设置一个计时器,

这样就保证一段时间内只会触发最后一次。

截流就是判断计时器是否存在,存在就不执行,等到计时器执行执行之后,

才允许新的执行。

3-使用场景

一般都是用来进行一个性能优化,比如输入框一般就是使用防抖来进行一个

智能提示,而截流一般就是图片这种进行一个懒加载。

12-js,html,css是什么?

按照我的理解,应该从html来讲起。html是一个标记性语言,它主要是用来定义和展示页面的结构,

而css就孕育而生,它是用来给网页的结构和元素添加样式的,使得网页具有更好的观赏和交流性。

html+css的是静态网页,只能看但是没有功能。js的功能就来了,Js 可以用来控制网页的行为,

如响应用户的输入、操作DOM(文档对象模型)、它使网页变得动态和交互性强。

而微软提出的ajax更是让js更上一层楼,那就是它可以在不进行网页刷新的情况下进行网络通信。

这一特性使得 JavaScript 成为了非常热门的前端开发语言之一。

13-vue是什么?(和js对比的好处)

Vue.js 相对于原生 JavaScript(即纯 JavaScript)有许多优势,特别是在构建复杂的应用程序时。以下是 Vue.js 的一些主要优点:

1. 双向数据绑定

Vue.js 提供了双向数据绑定的能力,这意味着当模型(数据)发生变化时,视图(DOM)会自动更新;反之亦然。这大大简化了数据同步的过程,而使用原生 JavaScript 时,需要手动编写大量的代码来保持视图与数据的一致性。

2. 组件化

Vue.js 的一个关键特性是其强大的组件系统。组件可以被重用,这使得代码更加模块化和易于维护。每个组件都有自己的作用域和生命周期,这有助于隔离和管理不同部分的状态。

3. 易于学习和使用

Vue.js 的学习曲线相对较低,入门门槛不高。它提供了简洁的 API 和文档,使得开发者可以很快地上手并开始构建应用程序。

4. 渲染性能

Vue.js 使用虚拟 DOM(Virtual DOM)来提高渲染性能。它通过diff算法比较新旧虚拟 DOM 树来找出最小的变化集,并仅更新必要的部分,从而减少浏览器的重绘次数。

14-作用域

作用域是什么?

作用域是值得变量和函数生效的区域范围

有几种作用域?

一共有三种作用域,全局作用域,函数作用域,块级作用域。

块级作用域的形成是let,const和{}形成的,在块级作用域中是不能

在let和const变量声明前进行使用的,因为会造成暂时性死区。

15-组件通讯

组件的通讯,我一下记不太清一共有多少种了。我边讲。

1-defineProps,父给子传值

2-defineEmits,发布订阅机制,父组件订阅一个事件,子组件发布该事件

3-v-model,这是一个语法糖,类似于发布订阅,父组件将绑定的属性

传给子组件,订阅一个事件叫做update:xxx,子组件改动属性就会发布这个

事件,

4-Provide/Inject

5-pinia/vuex

16-Vue生命周期和钩子函数

vue3使用setup函数来移除了BeforeCreate和created钩子函数,

  • onBeforeMount: 在组件挂载之前调用。
  • onMounted: 在组件挂载完成后立即调用。
  • onBeforeUpdate: 在组件更新之前调用。
  • onUpdated: 在组件更新完成后立即调用。
  • onBeforeUnmount: 在组件卸载之前调用。
  • onUnmounted: 在组件卸载之后立即调用。
  • onActivated: 如果组件是 <KeepAlive> 缓存的一部分,则此钩子会在组件被激活时调用。
  • onDeactivated: 如果组件是 <KeepAlive> 缓存的一部分,则此钩子会在组件被停用时调用。

17-react和vue的区别

我个人认为的react和vue的区别在于一下几点吧,

1.设计理念不同

react其设计理念是组件化开发。React主张使用JavaScript来处理更多的事情,推崇函数式编程,强调单向数据流,

设计模式是MVC模式,注重与MVC里面的V,也就是view层。react应用中数据对象是不可变的,需要使用setState方法更新状态;

而vue的话,设计理念是一个MVVM,用户只需要注重与M层的一个变化就可以了。因为vue底层就会帮我进行一个页面的更 新,页面的更新也会改动数据。

2.Diff算法的区别

React:React的diff算法称为Reconciliation,它通过比较虚拟DOM树来找出需要更新的部分。React的diff算法主要优化了树的遍 历,采用双端比较策略,提高了diff效率。

Vue:Vue的diff算法也借鉴了React的双端比较策略,但在此基础上进行了优化。Vue的diff算法在比较过程中会跳过静态节点,从而 提高渲染性能。

3.语法不同

React使用JSX语法,将HTML结构嵌入到JavaScript代码中,使得组件的结构和逻辑更加紧密。JSX需要通过Babel等工具转换成浏览器可识别的JS代码。

Vue:Vue使用模板语法,将HTML、CSS和JavaScript分离,更符合传统前端开发者的习惯。Vue的模板语法简洁明了,易于理解

18-this指向问题

this,apply,call,bind 超详细合集 - 掘金 (juejin.cn)

19-Promise

Promise是JavaScript中用于处理异步操作的一种对象,解决了回调地狱的问题,以下是Promise的五个关键点:

  1. 三种状态:

    Promise对象有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。当Promise被创建时,它处于pending状态;当异步操作成功完成时,它变为fulfilled状态;如果异步操作失败,则变为rejected状态。

  2. 状态的不可逆性:

    一旦Promise对象的状态从pending变为fulfilled或rejected,这个状态就不可再改变,即Promise对象的状态是永久性的。

  3. 链式调用:

    Promise支持链式调用,这意味着可以在一个Promise完成后继续调用另一个Promise,从而形成一系列异步操作。这是通过在Promise上调用.then()方法实现的,它返回一个新的Promise。

  4. 错误捕获:

    Promise提供了.catch()方法来捕获在执行过程中可能出现的错误。如果在Promise链中的任何地方发生错误,都可以被.catch()捕获,从而避免程序崩溃,并允许开发者对错误进行处理。

我一般不怎么使用Promise,而是使用async和await,它们是语法糖本质还是Promise,但是写起来会更加简洁和语义化。但是它身上的一些静态方法我使用过。Promise.all,接受的是一个promise数组,只有当所有promise的状态变成了fulfilled的时候,它就会返回一个新的promise。我使用过它进行一个大文件分片的上传。用它来进行一个并发网络请求发送。

20-let 、var 和const的区别

let和const 与var有什么区别

let和const 是es6的新语法,在函数预编译的时候会进行变量提升,这样在变量还没有赋值的时候就可以进行访问。

但是let和const不会,而且let和const遇到{}会形成块级作用域,并且let和const在声明之前是不能访问的,也不能访问

外部具有相同名字的变量因为会形成暂时性死区。这就是let、const和var的区别。

let和const的区别

它们两个的区别主要在let是声明变量,而const是声明常量的。

21-说说类型判断

类型判断我一共知道以下几种

  1. typeof

    除了null以外的基本类型都能判断,null会被判定为object。对象只能判断出function()和object类型,其他引用类型统一为obejct类型

  2. instanceof

    可以判断的出,但是无法知道具体类型。

  3. Object.prototype.toString()

    可以知道具体类型,返回的是一个字符串"[object Object]"

  4. Array.isArray()

    只用来判断数组的

22-重排(回流)和重绘

html树+css树 = 渲染树

渲染树+布局 = 布局树

进行分层然后图层合成光栅化最后进行cpu渲染。

重排和重绘的概念

重排和重绘是浏览器渲染页面内容时,经历的一系列步骤,其中包括重排(Reflow)和重绘(Repaint)。

重排是指浏览器为了重新渲染部分或整个页面,需要重新计算元素的尺寸和位置。这就是设计到需要进行重新

构建布局树,等等一系列操作。比较消耗性能。

重绘是指浏览器更新元素的外观样式,但不改变布局。消耗的性能就很小。

什么会造成重排和重绘

重排的原因:元素节点的删除和增加,一些改变位置大小还有文档流的操作都会涉及到重排。

重绘的原因:一些修改元素的背景颜色,修改字体样式这些就不会触发重排,但是会进行重绘渲染。

DocumentFragment文档碎片,减少JS直接操作dom元素的style

----- 1万条数据如何渲染
- 文档碎片
- requestAnimationFrame比setTimeout更好

刷帧率

减少offsetWidth offsetHeight getBoundingClient等属性的调用,立马触发重绘重排

23-闭包

是什么
- 根据作用域的规则,内部函数总是可以访问外部函数中的变量,
    又有当一个函数执行完毕之后函数的上下文一定会被销毁,那么为了同时
    满足这两个规则,闭包这个概念就出现了。
​
当内部函数被拿到外部函数之外调用,即使外部函数执行完毕,它被
内部函数引用的部分会以一个集合的方式保存在调用栈中。改集合就叫闭包。
  • 缺点: 容易内存泄露
  • 优点:创建私有变量,不污染全局变量
  • 应用场景:封装模块,

24-for in vs for of

for...in 循环

for...in 循环用于迭代对象的可枚举属性键。它可以用来遍历任何拥有属性的对象

  • 遍历的是对象的所有可枚举属性键。
  • 包括原型链上面的可枚举属性。
for...of循环

for...of 循环用于迭代可迭代对象(如数组、Set、Map 等)。

特点:
  • 遍历的是可迭代对象的值。

  • 适用于数组、Set、Map 等可迭代对象。

  • 保证了遍历的顺序,对于数组来说是按照索引的升序。

    普通对象无法使用因为它们是不可迭代的。

25-常用的数组遍历的方法

普通for循环,for of ,forEach ,map , reduce

26- 介绍一下jwt

jwt全面jsonwebToken,主要是用来进行一个安全的校验。前端在登录的时候向后端发送请求,

成功就会根据用户的信息还有私钥根据加密方式生产一串hash字符串也就是令牌,然后返回。之后的每次

请求都需要携带这个令牌给后端进行权限和安全的校验。

27-介绍一下富文本

富文本就是你可以输入一串文字,可以对文字进行一些样式的设计,比如加粗变大啊,图像、链接、表格都可以写,类似于md文档那种。

28-v-for 和key

15张图,20分钟吃透Diff算法核心原理,我说的!!! - 掘金 (juejin.cn)

vue里面v-for 为什么需要给每个元素添加一个key是为了高效的更新虚拟DOM,其实不只是 vuereact 中在执行列表渲染时也会要求给每个组件添加上 key 这个属性。

要讲清楚为什么可以高效更新虚拟DOM就必须了解Diff算法,Diff算法是一种对比算法。对比两者是旧虚拟DOM和新虚拟DOM

vuereact 的虚拟 DOMDiff 算法,:

  • 同一层级的一组节点,他们可以通过唯一的 id 进行区分。

  • 当页面的数据发生变化时,Diff 算法只会比较同一层级的节点:

    • 如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点以后的子节点了。
    • 如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。

29-v-if,v-show

两者都可以进行一个元素的显示和隐藏,但是v-if进行元素隐藏是直接删除dom节点,而v-show是

display:none,一般如何你是想平繁动态切换就使用v-show,用完就不用的就用v-if.

30-路由守卫

路由守卫分为3大类,
  • 全局守卫:它们会在每个路由变化时被调用,适用于所有路由。
  • 路由独享守卫:只针对特定的路由进行调用。
  • 组件内守卫:在组件内部定义,仅对该组件的路由变化有效。
  1. 全局守卫:

    • beforeEach: 在每个路由改变之前执行的守卫。常用于权限检查、登录验证等。
    • beforeResolve: 在路由解析前调用,用于拦截导航到同一路由的情况。
    • afterEach: 每个路由改变后都会调用的守卫。通常用于在路由改变后进行一些操作,如修改标题、滚动位置等。
  2. 路由独享的守卫:

    • beforeRouteEnter: 当进入一个路由时,在渲染该路由对应的组件之前被调用。
    • beforeRouteUpdate: 当进入一个已经存在的路由时被调用,通常用于数据更新。
    • beforeRouteLeave: 当离开一个路由时被调用,通常用于确认用户是否要离开当前页面,防止未保存的数据丢失。

一般路由守卫就是用来进行登录验证,权限控制。这两个功能我都使用和实现过。

登录验证就是判断用户是否进行过登录,然后一些非白名单的页面就进行校验,没有则跳转login登录页这样。

权限控制就是做后台管理系统的时候,进行过权限的控制。当时我是自定义了一个全局指令叫v-Permiss然后绑定需要

进行权限校验的元素,没有权限则隐藏该元素。

31-组件插槽

组件插槽的基本概念:
  1. 默认插槽(匿名插槽)

    • 在 Vue.js 中,如果你在组件的标签内部添加了一些内容,这些内容将会被传递到组件内部的一个默认插槽中。
    • 在组件的模板部分,你可以使用 <slot> 标签来指定这些内容的渲染位置。
  2. 具名插槽

    • 当一个组件需要多个插槽时,你可以给每个插槽命名,这样你就可以控制内容在不同的位置渲染。
    • 在父组件中使用 <template v-slot:slotName>(简写为 #slotName)来指定内容应该被渲染到哪个具名插槽。
  3. 作用域插槽

    • 有时,插槽内容可能需要访问子组件的作用域内的数据。
    • 在 Vue.js 中,你可以通过在 <slot> 标签上绑定属性来将子组件的数据传递给插槽。
    • 父组件可以通过 <template v-slot:slotName="slotProps"> 来接收这些数据,并在插槽内容中使用它们。

这些插槽我全部都使用过,具名插槽是我在手写vue-router的时候使用过用于指定渲染的插槽位置。

作用域插槽就是在对KeepAlive组件进行持久化都时候,在<router-view> 组件内部使用了一个作用域插槽,

并将当前路由匹配到的组件作为 Component 变量传递给插槽。也就是KeepAlive组件进行一个持久化。

32-vite和webpack

vite保留了esm的模块化这是浏览器原生支持的,让代码不像传统的构建工具一样需要去分析引入,打包构建,而是直接保持模块化,

webpack是commonJS浏览器读不懂,需要进行一个改变。

vite build是用go语言写的,多线程确实构建要比webpack块。

但是听说之前webpack的作者用rust底层写了一个叫做turbopack比vite更快

省去大量的编译时间,让代码更改后的响应速度大量提升。

一些浏览器是不认识import的(es6新语法)

可以在script标签中加入type="module"

代码压缩底层是使用的roll-up

热模块更新(HMR)是一种功能,允许在不重新加载整个页面的情况下,只更新页面上发生变化的模块。这意味着当你修改代码时,Vite 能够只重新编译和更新那些变化的模块,而不是整个应用,从而提供了更快、更流畅的开发体验。

  1. 本地开发的构建速度快,由于Vite是基于ESMesbuild的,所以在本地开发时整体的构建速度会比webpack更快
  2. 使用简单,Vite内置了很多loader和配置,让开发者可以零配置跑起来一个项目,而webpack则是需要写很多复杂的配置

33-Vite 中的热模块更新是如何工作的?

在 Vite 中,热模块更新是通过以下步骤实现的:

  1. 检测文件更改:Vite 监听项目文件系统的变化,比如打包的时候会使用到文件内容生成的hash值来检测文件是否更改。
  2. 编译更改的模块:一旦检测到文件更改,Vite 会重新编译受影响的模块。又因为Vite采用了esm的的模块化,所以无需更新其他模块内的代码。

以下是 Vite 中 HMR 的一些特点:

  • 即时反馈:更改代码后,几乎立即就能看到页面上相应的更新,无需手动刷新页面。
  • 保留应用状态:由于整个页面不需要重新加载,因此应用的状态(如变量状态、组件状态等)可以被保留。
  • 高效的更新:只有更改的模块会被重新编译和更新,而不是整个应用。
  1. Vite本地启动时会创建一个WebSocket连接,同时去监听本地的文件变化
  2. 当用户修改了本地的文件时,WebSocket的服务端会拿到变化的文件的ID或者其他标识,并推送给客户端
  3. 客户端获取到变化的文件信息之后,便去请求最新的文件并刷新页面

34-同源策略

同源策略本质是一种安全措施,用于限制一个网页的脚本与另一个来源的资源进行交互。这项政策旨在保护用户数据免受恶意脚本的攻击,防止数据泄露和其他安全风险。

1-JSONP

利用script标签不受同源策略的影响,需要服务器端的支持,将数据包裹在一个回调函数中返回。

2-设置Cors

服务器设置特定的 HTTP 请求头来实现,在请求头中加入Access-Control-Allow-Origin,可以让

浏览器对指定的请求源进行放行。服务器也可以设置一些设置比如指定允许的 HTTP 头部和请求方法。

3-服务器代理

浏览器的同源策略只会限制浏览器的网络请求,但是如果进行代码的话,那么就是服务器与服务器进行通信,然后设置的代理服务器和浏览器是同源的就不受同源策略的约束。

4-WebSocket

WebSocket 协议不受同源策略的限制,可以用来传输跨域数据

5-window.postMessage

可以在不同源的窗口之间传递消息。

35-数组去重

1-使用set进行数组去重,Array.from(new Set(arr));
2-数组排序后进行手动去重(双指针)
3-定义一个新数组通过includes和indexOf都可以进行去重

36-图片懒加载

是什么?

图片懒加载的原因是因为<img>标签设置了src属性,浏览器就会自动去进行网络请求下载资源。

但是一个项目可能有很多图片,同时进行网络请求会减慢项目的启动速度。所以可以进行懒加载,

先对屏幕内的图片进行网络请求,在用户将会滚动到图片位置时,再发送请求加载图片。

怎么做?

我的项目中是使用了IntersectionObserver进行一个元素的观察,它是浏览器的一个原生API。可以

对元素进行观察,当元素进入观察的视口内就会触发回调函数,此时就可以进行一个图片url的设置,

浏览器将会自动进行网络请求。一个这个url的值存储在data-src中的。

这就是我对图片懒加载的理解。

37-数据基本类型和判断数据基本类型

基本数据类型:

number,string,boolean,null,undefined,bigint,symbol(新语法)

判断基本数据类型

type方法除了null之外都可以判断,instanceof是判断复杂数据类型,

要想详细判断基本数据类型和复杂数据类型需要使用Object原型上的toString方法

Object.prototype.toString.call();

38-div的隐藏方法

1.display:none; 无文档流 , 无法绑定点击事件

  1. opacity:0 有文档流, 可以触发点击事件
  2. width:0 height:0 无文档流,无法绑定点击事件
  3. visbility:hidden 无文档流,无法绑定点击事件
  4. clip-path: polygon(50px 50px, 100px 100px, 0 100px, 50px 50px);(三角形)有文档流,无法绑定事件

39-get和post的区别

  • GET 适合用于获取数据,且数据量不大,不包含敏感信息。

    有长度限制一般是1-2kb根据浏览器而定,

    get请求是将请求的一些数据用?拼接在url中,不安全,

  • POST 适合用于提交数据,比如登录、注册等,

    对比GET来说POST的请求的数据在请求体中,相对更加私密和安全

  • GET 请求可以被浏览器缓存。

  • POST 请求不会被浏览器缓存。

根据restful准则 一切皆资源 统一的接口规范

GET 请求

POST 新增

PATCH/PUT 修S改

DELETE 删除

40-输入url后会发生什么

- 渲染页面
    1. 渲染页面:
​
   - 下载HTML:服务器响应请求,浏览器开始下载HTML内容。
   - 构建DOM树:浏览器解析HTML标签,在内存中构建DOM树。
​
2. 处理CSS和渲染树:
​
   - 下载CSS样式表:浏览器解析HTML中的`<link>`标签,下载CSS样式表。
   - 构建CSSOM树:浏览器解析CSS文件,构建CSSOM(CSS Object Model)树。
   - 构建渲染树:将DOM树和CSSOM树结合,构建渲染树(也称为布局树)。
​
3. 布局和绘制:
​
   - 布局:浏览器计算每个节点的确切位置和大小,生成布局树。
   - 绘制:浏览器将布局后的节点绘制到屏幕上。交给GPU渲染
​
4. JS是单线程 浏览器是多线程的
​
5. img link script ...浏览器会启动新的下载线程
​
6. 上高速 堵车
​
7. 有必要同时并发那么多图片

41-proxy和defineProperty的区别

ProxyObject.defineProperty 都是 JavaScript 中用于操作对象属性的行为,但它们之间存在一些关键的区别。

Object.defineProperty

  • 基础Object.defineProperty 是 ES5 引入的方法,用于直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回该对象。
  • 单一属性操作:它一次只能定义或修改一个属性。
  • 数据描述符和存取描述符:可以设置数据描述符(value, writable)和存取描述符(get, set)。
  • 无法监听数组索引赋值和长度变化:对于数组,defineProperty 不能监听到索引赋值和长度变化。
  • 无法监听对象属性的添加和删除:它不能监听到对象属性的添加或删除操作。
  • 性能影响:对于已经存在的对象属性进行操作时,性能影响较小。

Proxy

  • 基础Proxy 是 ES6 引入的构造函数,用于创建一个对象的代理,从而实现基本操作的拦截和自定义行为(如属性访问、赋值、枚举、函数调用等)。
  • 全面代理:它可以代理整个对象,而不是单个属性。
  • 捕获器(traps)Proxy 提供了13种捕获器,可以拦截并定义基本操作的自定义行为。
  • 监听数组索引赋值和长度变化:可以监听到数组索引赋值和长度变化。
  • 监听对象属性的添加和删除:能够监听到对象属性的添加(defineProperty)和删除(delete)操作。
  • 性能影响:由于代理了整个对象,可能在某些情况下会有更大的性能开销。
具体区别
  1. 操作范围

    • Object.defineProperty:仅限于单个属性。
    • Proxy:代理整个对象。
  2. 拦截功能

    • Object.defineProperty:仅能通过设置 setget 拦截属性的读取和设置。
    • Proxy:可以拦截包括但不限于属性的读取(get)、设置(set)、枚举(enumerate)、删除(deleteProperty)等13种操作。
  3. 对数组操作的支持

    • Object.defineProperty:无法有效监听数组索引的变动和长度的变化。
    • Proxy:可以监听数组的索引变动和长度变化。
  4. 对新增和删除属性的支持

    • Object.defineProperty:无法监听属性的新增和删除。
    • Proxy:可以监听属性的新增(通过 defineProperty)和删除(通过 delete 操作)。
  5. 性能

    • Object.defineProperty:对于现有属性的操作性能较好。
    • Proxy:可能因为代理整个对象而带来额外的性能开销。
结论

在选择 ProxyObject.defineProperty 时,如果需要代理整个对象并拦截多种操作,或者需要监听数组索引变化和对象属性的添加删除,Proxy 是更好的选择。如果只是需要针对对象的个别属性进行操作,且不需要考虑数组变化和属性的新增删除,Object.defineProperty 可能是更简单、更直接的选择。

42-Position有哪些会影响文档流的位置

  1. static:这是默认值。静态定位的元素处于正常的文档流中。它们的位置不会受到topbottomleftright属性的影响。
  2. relative:相对定位的元素相对于其正常位置进行定位。使用topbottomleftright属性可以设置元素相对于其正常位置的偏移。尽管元素的位置可能会改变,但它在文档流中的原始位置会被保留,也就是说,它仍然占据着原来的空间。
  3. absolute:绝对定位的元素相对于最近的非static定位的祖先元素进行定位。这意味着它们会脱离正常的文档流,不再占据原来的空间。它们的定位可以通过topbottomleftright属性来设置。
  4. fixed:固定定位的元素相对于浏览器窗口进行定位,并且它们也会脱离正常的文档流。与绝对定位类似,使用topbottomleftright属性可以设置其位置,但它们不会随页面滚动而移动。
  5. sticky:粘性定位是相对和固定定位的混合体。一个粘性定位的元素在滚动到其指定的偏移之前,表现得像相对定位的元素(即在文档流中保持其位置)。当达到指定的偏移量时,它将表现得像固定定位的元素(即固定在指定位置,不随滚动而移动)。

总结来说,absolutefixed定位的元素会脱离文档流,不再影响其他元素的布局,而relativesticky定位的元素虽然可以改变位置,但仍然保留在文档流中,占据原来的空间。static定位的元素则完全按照文档流的顺序和规则进行布局。

43-intanceof的原理

原理就是进行原型链的递归比较

function myInstance(instance,type){
if(instance===null)return false;
    if(instance.__proto__ === type){return true;}
    return myInstance(instance.__proto__,type);
}

44-ref和reactive的本质和原理

45-defineProperty和Proxy

46-MVVM详解

47-console.log([]===[])

答案为false。

因为===是严格比较,在比较基础类型的时候是进行值和类型的判断。

在对引用类型进行判断时,是对类型和地址进行判断。

48-const a= [1,2,3] 怎么做深拷贝,如果数据是不知道类型?

  1. 手写递归深拷贝,不需要原型链的属性
    function deepClone(targetObj){
        if (targetObj === null || typeof targetObj !== 'object') {
            return targetObj;
        }
        let newObj = {};
            for(let attr in targetObj){
                if(targetObj.hasOwnProperty(attr)){
                        newObj[attr] = deepClone(targetObj[attr]);
                    
                }
            }
            return newObj;
    }
    
  2. structuredClone(targetObj)

    • MessageChannel();

    const {port1,port2}=new MessageChannel();

    port1.postMessage(obj);

    port2.onmessage = e => console.log(e.data);//e.data就是新对象

  3. JSON.parse(JSON.stringify)

49-子元素设置水平垂直居中

1-flex布局

.parent{

display:flex;

justify-content:center;

align-items:center;

}

2-gird布局

.parent{

display:grid;

justify-content:center;

align-items:center;

}

3-position:absolute + transform

.parent{

position:relative;

}

.child{

position:absolute;

top:50%;

left:50%;

transform:translate(-50%,-50%);

}

4-父元素position:absolute + 子元素position:absolute

.parent {

position: absolute;

top: 0;

left: 0;

right: 0;

bottom: 0;

}

.child {

width: 200px;

height: 200px;

margin: auto;

position: absolute;

top: 0;

left: 0;

right: 0;

bottom: 0;

}

50-let b = "aaa"这个字符串占的内存空间

存储在堆中,占的大小

  • 每个字符 ‘a’ 占用2个字节。
  • 因此,字符串 "aaa" 总共占用 3 * 2 = 6 个字节。

v8是将字符串存储在堆中。因为字符串可能很长造成栈的溢出,俗称爆栈。

51-常见的网络协议

传输控制协议(TCP)

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。以下是TCP的一些关键特点:

  • 面向连接:在数据传输之前,TCP需要建立一个连接,这个过程称为三次握手。在连接建立后,数据传输开始,并且在传输完成后,连接将被终止。
  • 可靠性:TCP确保数据包的可靠传输。如果数据包在传输过程中丢失,TCP会重新发送这些数据包。
  • 有序性:TCP保证数据包按发送顺序到达。
  • 流量控制:TCP使用滑动窗口机制来控制数据流,避免发送方发送数据过快,接收方来不及处理。
  • 拥塞控制:TCP监视网络拥塞情况,并相应地调整其传输速率。
三次握手过程:
  1. SYN:客户端发送一个SYN(同步序列编号)到服务器,以开始一个新的连接。
  2. SYN-ACK:服务器收到SYN后,会应答一个SYN-ACK(同步确认应答)。
  3. ACK:客户端收到SYN-ACK后,发送一个ACK(确认应答)作为响应。
超文本传输协议(HTTP)

HTTP是应用层协议,主要用于Web服务器和客户端之间的信息传输。以下是HTTP的一些关键特点:

  • 无状态:HTTP协议本身是无状态的,这意味着服务器不会保存任何关于客户端过去请求的信息。
  • 简单性:HTTP协议相对简单,易于理解和使用。
  • 可扩展性:HTTP允许传输任意类型的数据,只需要在头部指定正确的Content-Type。
  • 请求/响应模式:客户端发送请求,服务器返回响应。
HTTP请求和响应结构:
  • 请求:包括请求行(方法、URL、HTTP版本)、请求头部、空行和可选的请求体。
  • 响应:包括状态行(HTTP版本、状态码、状态短语)、响应头部、空行和响应体。
超文本传输协议安全(HTTPS)

HTTPS是HTTP的安全版本,它在HTTP和TCP之间添加了一个加密层,通常是TLS(传输层安全性)或SSL(安全套接字层)。以下是HTTPS的一些关键特点:

  • 加密:HTTPS通过TLS/SSL对数据传输进行加密,保护数据不被窃听和篡改。
  • 认证:HTTPS提供服务器认证,确保用户连接到的是预期的服务器。
  • 完整性:HTTPS确保数据在传输过程中未被修改。
HTTPS工作流程:
  1. TCP连接:客户端和服务器首先建立TCP连接。
  2. TLS握手:在TCP连接建立后,客户端和服务器进行TLS握手,协商加密算法和交换密钥。
  3. 加密数据传输:一旦TLS握手完成,客户端和服务器使用协商好的密钥对HTTP数据进行加密传输。
  4. 结束TLS连接:当HTTP传输完成后,TLS连接将被终止。

HTTPS广泛用于网上银行、电子商务和其他需要处理敏感信息的网站,以确保数据的安全和隐私。随着网络安全意识的提高,HTTPS的使用也越来越普遍。

52-图片的格式?有什么不同

PNG(Portable Network Graphics)
  • 用途:适用于网页设计、透明背景的图像、图标等。

  • 特点

    • 支持无损压缩,图像质量不会下降。
    • 支持透明背景和半透明效果。
    • 可以包含较长的文件名和详细图像数据。
    • 支持交错(渐进显示),适合网络传输。
SVG(Scalable Vector Graphics)
  • 用途:适用于矢量图形,如图标、图表、网页设计元素等。

  • 特点

    • 基于XML的矢量图像格式,文件大小通常很小。
    • 可以无限放大而不失真。
    • 支持动画和交互性。
    • 不适合复杂的位图图像。
WebP
  • 用途:适用于网络图像,特别是需要压缩的图片。

  • 特点

    • 由Google开发,旨在加快图片的加载速度。
    • 支持有损和无损压缩。
    • 通常比JPEG和PNG格式更小的文件大小,但保持了较高的图像质量。
    • 支持透明背景和动画。
JPG / JPEG(Joint Photographic Experts Group)
  • 用途:适用于照片和复杂图像。

  • 特点

    • 采用有损压缩,可以大幅减小文件大小,但会损失一些图像质量。
    • 文件大小相对较小,适合网络传输。
    • 不支持透明背景。
    • 不适合包含文字或线条的图像,因为压缩可能会导致锯齿状边缘。
区别:
  • 压缩类型:PNG和SVG通常是无损压缩,而JPG和WebP通常是有损压缩。无损压缩保留了图像的所有数据,而有损压缩则牺牲了一些质量以获得更小的文件大小。
  • 文件大小:有损压缩的格式(如JPG和WebP)通常比无损压缩的格式(如PNG)文件大小更小。
  • 图像质量:无损格式在放大时不会失真,而有损格式可能会出现模糊或压缩伪影。
  • 透明度支持:PNG和WebP支持透明背景,而JPG不支持。
  • 适用场景:SVG适用于矢量图形,PNG适用于需要透明度的图像,JPG适用于照片,WebP则适用于需要压缩的网络图像。

53-对称加密和非对称加密的区别

对称加密(Symmetric Encryption)
  1. 密钥的使用

    • 对称加密使用相同的密钥(或密码)进行加密和解密。
    • 密钥必须保密,并且需要在通信双方之间安全地共享。
  2. 速度

    • 对称加密算法通常比非对称加密算法快得多,因为它们通常更简单。
  3. 算法示例

    • DES(Data Encryption Standard)
    • AES(Advanced Encryption Standard)
    • RC4(Rivest Cipher 4)
  4. 安全性

    • 安全性主要依赖于密钥的保密性。如果密钥泄露,加密的信息就可能被解密。
  5. 用途

    • 适用于大量数据的加密,如数据库加密、文件加密等。
非对称加密(Asymmetric Encryption)
  1. 密钥的使用

    • 非对称加密使用一对密钥:公钥和私钥。
    • 公钥可以公开分享,用于加密信息;私钥保密,用于解密信息。
  2. 速度

    • 非对称加密算法通常比对称加密算法慢,因为它们涉及更复杂的数学运算。
  3. 算法示例

    • RSA(Rivest-Shamir-Adleman)
    • ECC(Elliptic Curve Cryptography)
    • DSA(Digital Signature Algorithm)
  4. 安全性

    • 安全性基于数学难题,如大数分解或椭圆曲线离散对数问题,这些问题在当前计算能力下难以解决。
  5. 用途

    • 适用于密钥交换、数字签名、安全电子邮件等。
主要区别总结:
  • 密钥数量:对称加密使用一个密钥,非对称加密使用两个密钥(公钥和私钥)。
  • 密钥分发:对称加密需要安全地分发密钥,而非对称加密的公钥可以公开分发。
  • 性能:对称加密通常更快,非对称加密更慢。
  • 安全性:对称加密的安全性依赖于密钥的保密性,而非对称加密的安全性依赖于数学难题。
  • 用途:对称加密适用于加密大量数据,非对称加密适用于密钥交换和数字签名。

在实际应用中,对称加密和非对称加密经常结合使用,以充分利用它们的优势。例如,可以使用非对称加密来安全地交换对称加密的密钥,然后使用对称加密来加密实际的数据传输。

54-async & await 为什么比promise好

只是语法糖,本质还是promise,但是给我进行封装。使得更加的语义化。

并且代码更简洁,可以直接方便使用try,catch进行捕获。使用 async/await 可以更容易地调试异步代码,因为开发者可以设置断点并在 await 语句处暂停执行。

55-js的几个异步操作

56-Vue3 diff vs Vue2 diff

Vue 3 中的虚拟 DOM diff 算法相较于 Vue 2 进行了多项优化,以提高性能和效率。以下是 Vue 3 diff 算法的一些主要优化点:

1. 双端比较算法

Vue 3 继承并改进了 Vue 2 的双端比较算法,该算法在比较新旧 children 的过程中,会从两个列表的头部和尾部开始比较,寻找相同节点,这样可以减少不必要的节点比较,提高比较效率。

2. 静态节点优化

Vue 3 中,编译器能够识别静态节点和静态子树,并在 diff 过程中跳过它们,因为这些节点在后续渲染中不会发生变化。这样可以减少不必要的比较和重渲染。

3. Block Tree

Vue 3 引入了 Block Tree 的概念,它将模板分割为多个块,每个块包含了动态节点的信息。在更新过程中,Vue 3 只需要遍历包含动态内容的块,而不是整个虚拟 DOM 树,这样可以大大减少更新时的计算量。

4. Fragment 和 Teleport

Vue 3 支持了 Fragment(允许组件有多个根节点)和 Teleport(允许将子节点渲染到 DOM 树的其他位置)等新特性,这些特性对 diff 算法也进行了相应的优化。

5. 更高效的节点复用

Vue 3 在节点复用时进行了优化,它会尽可能复用已有节点,减少创建新节点和删除旧节点的操作,从而提高性能。

6. 属性更新优化

Vue 3 对属性更新进行了优化,它只更新变化的属性,而不是全部重新设置属性,减少了 DOM 操作。

7. 事件监听器缓存

Vue 3 对事件监听器进行了缓存,避免了重复绑定和移除事件监听器,提高了效率。

8-块树 (Block Tree)

Vue 3 引入了块树的概念,它将模板分割为多个块,每个块包含了动态节点的信息。在 diff 过程中,只需要遍历包含动态内容的块,而不是整个虚拟 DOM 树。

具体优化点:
  • 碎片 (Fragment) : Vue 3 允许组件有多个根节点,这在 Vue 2 中是不允许的,这需要对 diff 算法进行相应的调整。
  • 静态提升 (Static Hoisting) : 静态节点和子树在 diff 过程中被提升,不会在每次渲染时重新创建。
  • 编译时优化: Vue 3 的编译器在生成渲染函数时,会进行更多的优化,比如将动态节点集中在一起,减少运行时的开销。
  • 动态节点优化: 动态节点的处理更加高效,比如动态属性和动态子节点的更新。

这些优化使得 Vue 3 在处理大型列表和复杂组件树时,能够提供更快的更新速度和更好的性能表现。

57-interface & type

nterface 不支持原始数据类型, type 支持

interface 支持继承, type不支持,但可组合

interface 用于类的实现,type适合于各种类型定义

interface 用于类的定义和约束, type 用于创建类型别名,简化复杂类型表达

interface 是面向对象设计模式,面向接口编程的核心概念

TypeScript 中的 type 和 interface:你真的了解它们的不同吗?在 TypeScript 这个强大 - 掘金 (juejin.cn)

58-三次握手,四次挥手

关于三次握手与四次挥手面试官想考我们什么?--- 不看后悔系列在面试中,三次握手和四次挥手可以说是问的最频繁的一个知识点 - 掘金 (juejin.cn)

想象你正在通过一个在线书店买书,这个过程就像计算机网络中的数据传输。

1. 应用层(Application Layer)
  • 比喻:你选择了一本书,并点击“购买”按钮。
  • 功能:应用层就像是你和书店的界面,它决定了你的请求(比如买书)如何被发送。
2. 传输层(Transport Layer)
  • 比喻:书店确认你的订单,并安排快递。
  • 功能:传输层确保你的购买请求(数据)被正确地发送和接收,就像快递公司确保包裹送达。
3. 网络层(Network Layer)
  • 比喻:快递公司决定通过哪条路线将书送到你家。
  • 功能:网络层负责找到数据传输的最佳路径,就像快递公司选择路线。
4. 数据链路层(Data Link Layer)
  • 比喻:快递在每个中转站进行检查和转发。
  • 功能:数据链路层确保数据帧(包裹)在网络中的每个跳点(中转站)之间正确传输。
5. 物理层(Physical Layer)
  • 比喻:快递员驾驶卡车或摩托车运送包裹。
  • 功能:物理层处理数据的实际传输,就像快递员使用交通工具运送包裹。
整个过程:
  • 你(发送方)通过应用层告诉书店(接收方)你想要买书。
  • 传输层确保这个请求被正确地发送。
  • 网络层找到从书店到你的家的最佳路线。
  • 数据链路层确保数据在每个中转站被正确处理和转发。
  • 物理层实际传送数据,通过互联网的电缆和路由器等物理媒介。

这样,你可以把每一层想象成完成不同任务的步骤,就像在线购物的过程一样,每一步都确保了整个过程的顺利进行。

59-tailwind有什么有点?

  1. 响应式设计:Tailwind 内置了响应式设计工具,允许你通过简单的类名来控制不同屏幕尺寸下的样式,如 md:text-center
  2. 原子化CSS:Tailwind 采用原子化 CSS 的方法,这意味着每个类都是独立的,只负责一件事情,这有助于减少重复的 CSS 代码。
  3. 性能优化:由于减少了不必要的 CSS 代码,Tailwind 可以帮助减少最终生成的 CSS 文件的大小,从而提高页面加载速度
  4. 定制化:虽然 Tailwind 提供了大量的默认样式,但你可以很容易地通过配置文件来自定义样式,以满足你的设计需求。

60-js的几个异步操作

  1. Promise
  2. setTimeout
  3. fetch
  4. XMLHttpRequest
  5. requestAnimationFrame
  6. File API
  7. Web Workers

61-宏任务和微任务

宏:

在 JavaScript 中,宏任务(macrotask)是一系列较大的任务,它们在事件循环中的处理顺序相对较低。常见的宏任务包括:

  1. setTimeout(fn, 0) :使用 setTimeout 函数设置的定时器,即使设置为 0,也不会立即执行,而是被加入到宏任务队列中。
  2. setInterval(fn, 0) :与 setTimeout 类似,使用 setInterval 设置的定时器,即使设置为 0,也不会立即执行。
  3. setImmediate(Node.js 环境) :在 Node.js 中,setImmediate 用于在当前事件循环的所有任务完成后立即执行一个函数。
  4. I/O 操作:如文件读取、网络请求等,这些操作完成后会作为宏任务被加入到队列中。
  5. 用户交互事件:例如点击事件、键盘事件等,这些事件处理函数会在事件触发后被加入到宏任务队列中。
  6. requestAnimationFrame:用于在浏览器下一次重绘之前执行的函数。
  7. requestIdleCallback:在浏览器空闲时执行的函数,这个宏任务在浏览器绘制完成之后执行。
  8. MessageChannel 消息MessageChannel 是一个高级 API,用于在不同的线程之间发送消息。
  9. postMessage:在不同的窗口或标签页之间发送消息。
  10. importScripts:在 Web Worker 中,用于加载脚本。
  11. XMLHttpRequest 事件XMLHttpRequest 对象的回调函数,如 onreadystatechange
  12. setImmediate(旧版) :在旧版 Node.js 中,setImmediate 用于在当前事件循环的所有任务完成后立即执行一个函数。
  13. I/O 完成事件:例如,fs.writefs.read 等文件操作完成后的回调函数。

这些宏任务会在事件循环的适当时间点被处理,但它们的处理顺序低于微任务。在 JavaScript 的事件循环中,宏任务在所有微任务处理完成后执行

微:
  • Promise 回调Promise 对象的 .then(), .catch(), 和 .finally() 方法。
  • MutationObserver 回调:用于监视 DOM 变化的观察器。
  • async/await 函数中的代码:在 async 函数中的代码,或者在 await 表达式之后的代码。
  • queueMicrotask:一个全局函数,允许你将一个函数排队为一个微任务。