前端面试题总结(一)

Promise.all()异常处理


promise.all中任何一个promise 出现错误的时候都会执行reject,导致其它正常返回的数据也无法使用。

解决办法:
  • 由于Promise.all(request).then(…).catch(…) 会在所有requestresolve时才会进then方法,并且把所有结果以一个数组返回,只要有一个失败,就会进catch。而如果在单个请求中定义了catch方法,那么就不会进Promise.allcatch方法。因此,可以在单个的catch中对失败的promise请求做处理,可以使成功的请求正常返回。

    function getData(api){
        return new Promise((resolve,reject) => {
          setTimeout(() => {
            var ok = Math.random() > 0.5  // 模拟请求成功或失败
            if(ok)
              resolve('get ' + api + ' data')
            else{
              reject('error') // 正常的reject
            }
          },2000)
        })
      }
      function getDatas(arr){
        var promises = arr.map(item => getData(item))
        return Promise.all(promises.map(p => p.catch(e => e))).then(values => { // 关键步骤,map(p => p.catch(e => e)) 在每个请求后加上 catch 捕获错误;
          values.map((v,index) => {
            if(v == 'error'){
              console.log('第' + (index+1) + '个请求失败')
            }else{
              console.log(v)
            }
          })
        }).catch(error => {
          console.log(error)
        })
      }
      getDatas(['./api1','./api2','./api3','./api4']).then(() => '请求结束')
    
  • 出现错误请求之后不进行reject操作,而是继续resolve('error), 之后同意交给promise.all()进行处理。

     function getData(api){
        return new Promise((resolve,reject) => {
          setTimeout(() => {
            var ok = Math.random() > 0.5  // 模拟请求成功或失败
            if(ok)
              resolve('get ' + api + ' data')
            else{
              // reject(api + ' fail')   // 如果调用reject就会使Promise.all()进行失败回调
              resolve('error')    // Promise all的时候做判断  如果是error则说明这条请求失败
            }
          },2000)
        })
      }
      function getDatas(arr){
        var promises = arr.map(item => getData(item))
        return Promise.all(promises).then(values => {
          values.map((v,index) => {
            if(v == 'error'){
              console.log('第' + (index+1) + '个请求失败')
            }else{
              console.log(v)
            }
          })
        }).catch(error => {
          console.log(error)
        })
      }
      getDatas(['./api1','./api2','./api3','./api4']).then(() => '请求结束')
    

数组中的第K个最大元素


在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 

示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 输出: 4 

说明:

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
思路:

我的解题思路是首先利用js中数组的方法sort()进行降序排序,在循环遍历排好序之后的数组,根据指定的k值与遍历的i值对比,返回得到相应的结果,其中要注意的是,由于数组遍历时下标从0开始,而k是从1开始,故返回结果中需要进行k-1再进行和i判断。

方法:
/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var findKthLargest = function(nums, k) {
    nums.sort((a,b) => b-a) //降序排序
    for(var i=0;i<nums.length;i++){
        if((k-1) == i){//i从0开始
            return nums[i]
        }
    }
};

一个页面有父子组件,进入之后的渲染顺序触发的生命周期是什么样的


Vue生命周期描述:在vue实例被初始化之后,触发beforeCreate钩子函数,然后开始进行数据观测和事件配置;实例创建完成之后立马触发created钩子函数,此时已经配置好数据观测和属性以及方法;之后开始编译模板,将data里的数据和vue语法写的模板编译成HTML,开始挂载HTML到对应的位置时触发beforeMount钩子函数,相关的render函数也首次被调用;当挂载到页面完成后触发mounted钩子函数;当数据发生更新时,触发beforeUpdate钩子函数,然后虚拟DOM开始重新渲染和打补丁,完成之后触发updated钩子函数;在实例销毁前触发beforeDestroy钩子函数,此时实例还可用,然后开始移除事件监听器,销毁子实例等等,完成之后触发destroyed。

  • created和mounted区别:参考:Vue生命周期中mounted和created的区别

    • created: 在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。此时操作DOM节点,找不到相应元素。
    • mounted: 在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
  • 子父组件加载顺序

    • 加载渲染过程:父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
    • 子组件更新过程:父beforeUpdate->子beforeUpdate->子updated->父updated
    • 父组件更新过程:父beforeUpdate->父updated
    • 销毁过程: 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

keep-alive 常用属性


keep-alive简介

keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
用法:

<keep-alive>
  <component>
    <!-- 该组件将被缓存! -->
  </component>
</keep-alive>
props 属性
  • include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
  • exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
  • max - 数字。最多可以缓存多少组件实例。

用法

<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。

当组件在 <keep-alive> 内被切换,它的 activateddeactivated 这两个生命周期钩子函数将会被对应执行。

 //组件 a
export default {
  name: 'a',
  data () {
    return {}
  }
}
<keep-alive include="a">
  <component>
    <!-- name 为 a 的组件将被缓存! -->
  </component>
</keep-alive>可以保留它的状态或避免重新渲染
<keep-alive exclude="a">
  <component>
    <!-- 除了 name 为 a 的组件都将被缓存! -->
  </component>
</keep-alive>可以保留它的状态或避免重新渲染

max:

最多可以缓存多少组件实例。一旦这个数字达到了,在新实例被创建之前,已缓存组件中最久没有被访问的实例会被销毁掉。

<keep-alive :max="10">
  <component :is="view"></component>
</keep-alive>
遇见vue-router

router-view也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存:

<keep-alive>
    <router-view>
        <!-- 所有路径匹配到的视图组件都会被缓存! -->
    </router-view>
</keep-alive>
问题
  • 如果只想router-view里面某个组件被缓存,怎么办?
    • 使用include/exclude
  • 增加router.meta属性
    • 第一种方法上面已经描述,下面说第二种方法
    • 增加router.meta属性
// routes 配置
export default [
  {
    path: '/',
    name: 'home',
    component: Home,
    meta: {
      keepAlive: true // 需要被缓存
    }
  }, {
    path: '/:id',
    name: 'edit',
    component: Edit,
    meta: {
      keepAlive: false // 不需要被缓存
    }
  }
]
<keep-alive>
    <router-view v-if="$route.meta.keepAlive">
        <!-- 这里是会被缓存的视图组件,比如 Home! -->
    </router-view>
</keep-alive>

<router-view v-if="!$route.meta.keepAlive">
    <!-- 这里是不被缓存的视图组件,比如 Edit! -->
</router-view>
实例
  • 假设这里有 3 个路由: A、B、C。
    • 需求: 默认显示 A,B 跳到 A,A 不刷新,C 跳到 A,A 刷新
实现方式:

在 A 路由里面设置 meta 属性:

{
    path: '/',
    name: 'A',
    component: A,
    meta: {
        keepAlive: true // 需要被缓存
    }
}

在 B 组件里面设置 beforeRouteLeave:

export default {
    data() {
        return {};
    },
    methods: {},
    beforeRouteLeave(to, from, next) {
         // 设置下一个路由的 meta
        to.meta.keepAlive = true;  // 让 A 缓存,即不刷新
        next();
    }
};

在 C 组件里面设置 beforeRouteLeave:

export default {
    data() {
        return {};
    },
    methods: {},
    beforeRouteLeave(to, from, next) {
        // 设置下一个路由的 meta
        to.meta.keepAlive = false; // 让 A 不缓存,即刷新
        next();
    }
};

这样便能实现 B 回到 A,A 不刷新;而 C 回到 A 则刷新。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值