开发中我们经常遇到这样的问题:每次切换页面,我需要在父组件重新请求一次要切换到的页面的一些状态和数据,然后把这些状态和数据传递给子组件,然后对这些数据进行加工渲染到页面上。
那么问题来了,我们的子组件如何确定自己能知道自己拿到的是最新的数据而不是上一次的数据呢?也就是说,在我子组件要对父组件传来的数据进行加工时如何保证这是我最新一次拿到的当前页面的数据?
举个例子:
我们将图片左端的滑块放置到60px位置上,然后在handleMouseup事件中更新释放滑块的状态并向父组件提交一次拖动的状态信息(比如image_id,xx.xx.height=60px等等这样的信息),在父组件中把这些状态信息通过axios.put方法放置到后端来存储,这样的话再次加载该图片进行请求时,就能请求到对应的滑块位置(xx.xx.height=60px这个信息),并根据这个信息进行重制滑块位置。这时当下次再次切换到当前图片的页面时,第一步我们需要在子组件的图片加载监听事件中添加一个设置滑块状态的监听器,第二步要在监听器中通过getBoundingClientRect()方法获取到获取该图片元素相对于视窗的位置集合。集合中有top, right, bottom, left等属性,把这些信息设置给子组件需要加工的信息中,第三步我们要重制滑块位置,比如我们把重制滑块位置的一系列方法放置在setting()函数中,并在监听器中调用setting()。这时问题来了:如何保证我们在重制滑块位置时拿到的是最新的数据值呢?要知道我们用的信息是父组件传递过来的,如果父组件请求xx.xx.height=60px等一系列信息时时间过长怎么办,我们立即调用setting是不是就会导致滑块高度缺失或者出现并不是height=60px的情况了?
解决方案1:定时器
setTimeout(() => { this.setting() }, 200)
优点:简洁明了
缺点:要注意父组件的异步事件队列和子组件的异步事件队列是几乎同时执行的,也就是说当axios的请求超过200毫秒还没返回时,子组件那边已经执行完setTimeout了,那进行设置滑块所用到的状态只能是老的状态,这就出现了状态缺失的问题。
解决方案2:监听保证顺序执行
在子组件中设置一个计数器,在父组件中监听这个计数器,当子组件执行完第二步时将计数器自增,这样父组件监听到改变并在watch中执行axios方法请求资源数据,并在拿到数据后调用子组件的setting方法
优点:稳定,严格保证了顺序执行
缺点:流程复杂,代码繁琐,不利于维护
解决方案3:promise
将请求axios的方法头加上async,在axios前加await,并将该方法拿到的promise赋值给一个参数,再把这个参数传递给子组件,这样我们只需在子组件中await这个参数(等promise拿到参数状态置为fullfilled)再执行setting进行滑块位置的设定即可
优点:稳定,代码简洁便于维护
缺点:要保证在页面刷新时执行一次传送从而使子组件重制promise状态
综上所述:最理想的解决方案是第三种,这充分利用到了async和await的简化promise并保证拿到返回的结果再去执行下一步