Promise.all()异常处理
promise.all
中任何一个promise
出现错误的时候都会执行reject
,导致其它正常返回的数据也无法使用。
解决办法:
-
由于
Promise.all(request).then(…).catch(…)
会在所有request
都resolve
时才会进then
方法,并且把所有结果以一个数组返回,只要有一个失败,就会进catch
。而如果在单个请求中定义了catch
方法,那么就不会进Promise.all
的catch
方法。因此,可以在单个的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>
内被切换,它的 activated
和 deactivated
这两个生命周期钩子函数将会被对应执行。
//组件 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 则刷新。