问题描述
想象一种情景,比如我们在用 Vue 的 watch api时,我们想监听某个数据的变化,然后在回调函数中调用接口,可是接口调用一般是异步操作,有可能我们第二次调用接口比较快,而第一次调用接口比较慢,这样会导致页面上渲染的是第一次调用接口获取的数据,可是我们只想要最新的数据,该怎么办?
案例代码
let timer = 3000;
const getData = data =>
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(data);
}, timer -= 1000);
});
watch(() => state.name,
async (newValue, oldValue) => {
let r = await getData(newValue);
app.innerHTML = r;
}
);
state.name = 1;
state.name = 2;
这段代码的实际表现是会先渲染2再渲染1,不符合我们的实际要求
解决方案(Vue2)
- 我们可以通过闭包,来实现对每一次回调函数的状态修改
let timer = 3000;
const getData = data =>
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(data);
}, timer -= 1000);
});
let arr = [];
watch(() => state.name,
async (newValue, oldValue) => {
let flag = true;
while (arr.length > 0) {
let cb = arr.shift();
cb();
}
arr.push(() => { flag = false })
// 调用接口
let r = await getData(newValue);
if (flag) {
// 实际渲染效果
app.innerHTML = r;
}
}
);
state.name = 1;
state.name = 2;
解决方案(Vue3)
- Vue3为我们提供了一个api
onCleanup,我们可以通过这个api实现跟上面一样的操作
let timer = 3000;
const getData = data =>
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(data);
}, timer -= 1000);
});
watch(
() => state.firstName,
async (newValue, oldValue, onCleanup) => {
let flag = true;
onCleanup(() => {
flag = false;
});
let r = await getData(newValue);
if (flag) {
app.innerHTML = r;
}
}
);