上一篇文章分析了用Proxy代理问题,用户需要自己对原始对象数据进行深度代理,这一篇文章看看还有没有其他问题。先看一个例子:
<html>
<head>
<style type="text/css"></style>
</head>
<body>
<script>
let arr = [
{
id: 1,
msg: "arr_1",
},
{
id: 2,
msg: "arr_2",
},
];
let arrProxy = new Proxy(arr, {
get(target, key, receiver) {
console.log(`arrProxy get key: ${key}`);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
console.log(`arrProxy set key: ${key}, value: ${JSON.stringify(value)}`);
return Reflect.set(target, key, value, receiver);
},
});
arrProxy.unshift({
id: 0,
msg: 'arr_0'
})
</script>
</body>
</html>
这个例子对数组进行了Proxy代理。当在这个数组开始处增加一个元素时,我们看看打印结果:
get触发了多次,set也触发了多次。set为什么会触发多次呢?在数组最前面插入元素,依次会把数组之前的元素往后挪,最后把要插入的元素放到最开始处,最后还更新了length值,所以触发了多次set操作。我们想要的set触发后notify一次就好了,有没有办法做到这一点呢? 函数防抖就可以了,我们用setTimeout 处理一下这个抖动,代码如下:
<html>
<head>
<style type="text/css"></style>
</head>
<body>
<script>
let arr = [
{
id: 1,
msg: "arr_1",
},
{
id: 2,
msg: "arr_2",
},
];
let timerId = 0
let arrProxy = new Proxy(arr, {
get(target, key, receiver) {
console.log(`arrProxy get key: ${key}`);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
clearTimeout(timerId)
timerId = setTimeout(() => {
console.log(`arrProxy set key: ${key}, value: ${JSON.stringify(value)}`);
}, 0);
return Reflect.set(target, key, value, receiver);
},
});
arrProxy.unshift({
id: 0,
msg: 'arr_0'
})
</script>
</body>
</html>
在set中加了防抖处理,看一下打印结果:
把之前触发set后,notify多次的操作都给clear了,最后一个是更新length 操作,被保留下来了。其实这么干不太对,我们期望的是length操作触发set后不去notify,怎么才能做到这一点呢?判断一下key是否为length就可以了。代码如下:
<html>
<head>
<style type="text/css"></style>
</head>
<body>
<script>
let arr = [
{
id: 1,
msg: "arr_1",
},
{
id: 2,
msg: "arr_2",
},
];
let arrProxy = new Proxy(arr, {
get(target, key, receiver) {
console.log(`arrProxy get key: ${key}`);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
let isLength = key === 'length' ? true : false
if(!isLength){
console.log(`arrProxy set key: ${key}, value: ${JSON.stringify(value)}`);
}
return Reflect.set(target, key, value, receiver);
},
});
arrProxy.unshift({
id: 0,
msg: 'arr_0'
})
</script>
</body>
</html>
这样当修改length时触发set就不会去notify了。
这个例子我们只是对length简单处理了一下,vue3.0 当然会比这复杂的多。下一篇文章我们就看看Vue3.0 是如何利用 Proxy实现响应式系统的。