一个由父子组件传值和$nextTick引发的关于宏任务和微任务的思考

这一切要从最近接手了一段祖传的代码开始说起。。。

起因和解决方式 作为一名前端老司机(自封),也不知道是不是招我进来的老哥看上了我的项目经历还是老板的无意为之(年底都是老项目优化),总而言之我接手了一段老的n手(n>3)代码,虽然提交时间是一年前,但是这ES5语法仿佛是15-17年的产物,让我回想到我刚工作的时候接触的网页,有种亲切的感觉(不是)。
在一顿梳理之后,我把问题的目标锁定在了一对父子组件上,子组件内有两个函数:
  1. 根据watch监听的函数,在父组件上用data控制组件展示的同时,我们要在这里做一个localStorage.setItem和赋值子组件data的操作,在每次打开时传入当前定位城市。
  1. 一个需要localStorage.getItem获取数据然后做请求与后端交互的函数,原有逻辑会在父组件上通过ref去调用,为了逻辑分离和避免重复调用,不把(2)加入到(1)的逻辑里
如果是react的setState,我会选择把(2)函数传入setState的回调,但是这可是vue2啊。在他们两个同时调用的场景下,因为经过了watch的拦截,(2)肯定会先于(1)触发。于是,我们就在(2)调用localStorage.getItem和赋值子组件data的时候在Storage外层包裹上$nextTick,localStorage.getItem就能正确拿到数据了,完美~
父组件调用:
this.isshowseach = true; this.$refs.seachadrFuc.mapData(localStorage.getItem("currentCity"));

子组件watch和methods:
watch: { showOnoff: { handler(val) { console.log("showOnoff触发"); // 默认把当前定位的城市填入 this.selectCity = this.city; localStorage.setItem("selectCity", this.selectCity); } }, }, },

methods: { mapData(val) { console.log("mapData触发"); this.$nextTick(() => { this.getupList(); }); },getupList() { console.log(this.selectCity) //成功赋值为this.city }}

一个由父子组件传值和$nextTick引发的关于宏任务和微任务的思考
文章图片

分析: 【一个由父子组件传值和$nextTick引发的关于宏任务和微任务的思考】watch这里使用的Object.observe(proxy同理)监听,属于微任务,所以会比同步任务window.localStorage.getItem后执行。
$nextTick的原理是Promise.then、MutationObserver和 setImmediate又或者是setTimeout(fn,0),都属于宏任务,因此window.localStorage.getItem和赋值子组件data包裹上宏任务$nextTick后,又会比watch后执行。
谢谢观看!

    推荐阅读