前端高级工程师最全面试题-持续更新

1,promise.all 异常处理

/**通常处理多个请求的时候我们会用Promise.all()方法。该方法指当所有在可迭代参数中的 promises 已完成,
或者第一个传递的 promise(指 reject)失败时,返回 promise。但是当其中任何一个被拒绝的话。
主Promise.all([..])就会立即被拒绝,并丢弃来自其他所有promis的全部结果。*/


    var p1 = Promise.resolve(3).catch(function(err) {
      return err;
    });
    var p2 = Promise.reject(2).catch(function(err) {
      return err;
    });
    var p3 = new Promise((resolve, reject) => {
      setTimeout(resolve, 100, "foo");
    }).catch(function(err) {
      return err;
    }); 
    
    Promise.all([p1, p2, p3]).then(values => { 
      console.log(values); // [3, 2, "foo"]
    }).catch(function(err) {
      console.log(1); //不会走到这里
    });

2,vue3.0相关

1,vue的底层原理?
Answer:Vue是采用数据劫持配合发布者-订阅者模式,通过Object.defineProperty来()来劫持各个属性的getter和setter。在数据发生变化的时候,发布消息给依赖收集器,去通知观察者,做出对应的回调函数去更新视图。

2,vue3.0的新特性?
更小
更快
加强TypeScript支持
加强API设计一致性
提高自身可维护性
开放更多底层功能
1,更小当前最小化并被压缩的 Vue 运行时大小约为 20kB(2.6.10 版为 22.8kB)。Vue 3.0捆绑包的大小大约会减少一半,即只有10kB!
2,Object.defineProperty -> Proxy
Object.defineProperty是一个相对比较昂贵的操作,因为它直接操作对象的属性,颗粒度比较小。将它替换为es6的Proxy,在目标对象之上架了一层拦截,代理的是对象而不是对象的属性。这样可以将原本对对象属性的操作变为对整个对象的操作,颗粒度变大。
javascript引擎在解析的时候希望对象的结构越稳定越好,如果对象一直在变,可优化性降低,proxy不需要对原始对象做太多操作。
3,Virtual DOM 重构
vdom的本质是一个抽象层,用javascript描述界面渲染成什么样子。react用jsx,没办法检测出可以优化的动态代码,所以做时间分片,vue中足够快的话可以不用时间分片。
传统vdom的性能瓶颈:
虽然 Vue 能够保证触发更新的组件最小化,但在单个组件内部依然需要遍历该组件的整个 vdom 树。
传统 vdom 的性能跟模版大小正相关,跟动态节点的数量无关。在一些组件整个模版内只有少量动态节点的情况下,这些遍历都是性能的浪费。
JSX 和手写的 render function 是完全动态的,过度的灵活性导致运行时可以用于优化的信息不足
那为什么不直接抛弃vdom呢?

  • 高级场景下手写 render function 获得更强的表达力

  • 生成的代码更简洁

  • 兼容2.x
    vue的特点是底层为Virtual DOM,上层包含有大量静态信息的模版。为了兼容手写 render function,最大化利用模版静态信息,vue3.0采用了动静结合的解决方案,将vdom的操作颗粒度变小,每次触发更新不再以组件为单位进行遍历,主要更改如下

  • 将模版基于动态节点指令切割为嵌套的区块

  • 每个区块内部的节点结构是固定的

  • 每个区块只需要以一个 Array 追踪自身包含的动态节点 vue3.0将 vdom 更新性能由与模版整体大小相关提升为与动态内容的数量相关

4, 更多编译时优化

  • Slot 默认编译为函数:父子之间不存在强耦合,提升性能
  • Monomorphic vnode factory:参数一致化,给它children信息,
  • Compiler-generated flags for vnode/children types

5,选用Function_based API

1,vue3.0将组件的逻辑都写在了函数内部,setup()会取代vue2.x的data()函数,返回一个对象,暴露给模板,而且只在初始化的时候调用一次,因为值可以被跟踪。

2,新的函数api:const count = value(0)

value是一个wrapper,是一个包装对象,会包含数字0,可以用count.value来获取这个值。在函数返回的时候会关心是value
wrapper,一旦返回给模版,就不用关心了。

优点:即使count包含的是基本类型,例如数字和字符串,也可以在函数之间来回传递,当用count.value取值的时候会触发依赖,改值的时候会触发更新。

3,计算属性返回的也是这个值的包装。

4,onMounted生命周期函数直接注入。

3,常见考题

1、vue中computed和watch的区别?
computed是通过几个数据的变化,来影响一个数据,而watch,则是一个数据的变化,去影响多个数据。

2、vue里data为什么是函数而不是对象?
如果写成对象,当组件被复用时,那么多个组件实例就会共用同一个data对象,这样改变其中一个实例的data,就会改变所有的。
因此写成函数返回值的形式,使每个组件实例都拥有自己的私有数据空间,不会造成混乱。

3、vue里数组改变为什么有的会渲染,有的不会渲染?
对用数组的变异方法(push、pop、sort等)进行数组操作时可以达到视图的重新渲染,因为vue对这些方法进行了包裹。 Vue
不能检测以下数组的变动: 利用索引直接设置一个数组项时 修改数组的长度时
因为这样的操作vue根本没法做一个Object.defineProperty处理。
解决方法:vm.$set(vm.items, indexOfItem, newValue)

4、update里去改变data值会有问题吗? 由于数据更改导致的虚拟 DOM
重新渲染和打补丁,在这之后会调用update钩子。应避免在此期间更改状态,否则可能导致死循环。

5、加载数据在created好还是在mounted好,两者区别?
在created比较好,如果在mounted钩子函数中请求数据可能导致页面闪屏问题。 两者区别:
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。

6、vue通信的几种方式
props和$emit, $parent 和 c h i l d r e n , ( 另 有 : children, (另有: childrenroot:获取根实例) provide / inject, ref / refs, vuex(状态管理器), localstorage和sessionStorage

7、vue单向数据流 父级 prop
的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。 注意在
JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop
来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态。

8、vue服务端渲染 Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作
DOM。然而,也可以将同一个组件渲染为服务器端的 HTML
字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序

9、vue项目性能优化
1、使用v-if代替v-show
2、v-for必须加上key,并避免同时使用v-if
3、事件及时销毁
4、图片需要裁剪,一般使用二倍图即可,尽量使用webp图片,如果使用了vue-lazyload插件,可以使用以下方法一键替换webp(替换使用v-lazy指令的图片)
5、资源提前请求
经测试,Vue项目中各文件的加载顺序为:router.js、main.js、App.vue、[-page-].vue、[component].vue
其中,router的加载时间相比于page.vue快近100ms,如果page.vue的文件较多,时间差异会更大
所以,可以在页面挂载、渲染的同时去请求接口数据,如在router.js中请求数据:

6、异步路由

使用异步路由可以根据URL自动加载所需页面的资源,并且不会造成页面阻塞,较适用于移动端页面

建议主页面直接import,非主页面使用异步路由

使用方式:

{
 path: '/order',
 component: () => import('./views/order.vue')
}

7、异步组件 不需要首屏加载的组件都使用异步组件的方式来加载(如多tab),包括需要触发条件的动作也使用异步组件(如弹窗)
使用方式为:v-if来控制显示时机,引入组件的Promise即可

<template>
 <div>
 <HellowWorld v-if="showHello" />
 </div>
</template>
<script>
export default {
 components: { HellowWorld: () => import('../components/HelloWorld.vue') },
 data() {
 return {
 showHello: false
 }
 },
 methods: {
 initAsync() {
 addEventListener('scroll', (e) => {
 if (scrollY > 100) {
 this.showHello = true
 }
 })
 }
 }
}
</script>

8、使用轻量级插件、异步插件
使用webpack-bundle-analyzer查看项目所有包的体积大小,较大的插件包尽量寻找轻量级的替代方案

首屏用不到的插件、或只在特定场景才会用到的插件使用异步加载(如定位插件,部分情况可以通过URL传递经纬度;或生成画报插件,需要在点击时触发);插件第一次加载后缓存在本地,使用方式为:

// 以定位插件为例
const latitude = getUrlParam('latitude')
const longitude = getUrlParam('longitude')
// 如果没有经纬度参数,则使用定位插件来获取经纬度
if (!latitude || !longitude) {
 // 首次加载定位插件
 // webpack4写法,若使用webpack3及以下,则await import('locationPlugin')即可
 if (!this.WhereAmI) this.WhereAmI = (await import('locationPlugin')).default
 // do sth...
}

9、公用CDN 使用公用的CDN资源,可以起到缓存作用,并减少打包体积

10、减少网络请求 浏览器对同一时间针对同一域名下的请求有一定数量限制(一般是6个),超过限制数目的请求会被阻塞
首屏尽可能减少同域名的请求,包括接口和js;按需减少首屏的chunk.js,合并接口请求

11、vue中不用vuex如何实现在任意子组件都可以访问一个全局的变量? 通过 $root 访问根实例可实现。

  • 2
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值