Vue2源码从零详解系列文章,没看过的同学可能需要看上一篇,vue.windliang.wang。从“./reactive”导入场景{观察};从“./watcher”导入观察者;const数据={a:1,b:2,c:3,};观察(数据);constupdateComponent=()=>{console.log(data.a+data.b);};newWatcher(updateComponent);constupdateComponent2=()=>{console.log(data.c);};newWatcher(updateComponent2);数据。a=2;data.a=3;data.b=4;data.c=5;newWatcher(updateComponent)会输出一次3进行依赖收集,newWatcher(updateComponent2)会输出一次3进行依赖收集。之后我们依次改变a、a、b、c的值,每次改变都会触发Watcher的执行,console.log会连续执行四次。试想一下,如果这里的console.log是一个渲染页面,那么改一次值再刷新页面会造成严重的性能问题,页面会一直变化。解决方案我们可以通过一个队列来收集所有的观察者。Watcher队列什么时候执行?为了等待所有的Watcher被收集,可以将Watcher的执行放在setTimeout中。这样,当主线程执行完毕后,Watcher队列才会执行。对于代码实现,我们可以为每个Watcher添加一个id。如果队列中已经有id,则不会加入队列。letuid=0;exportdefaultclassWatcher{constructor(Fn,options){this.getter=Fn;this.depIds=newSet();//有一个has函数来判断一个id是否存在this.deps=[];这个.newDeps=[];//记录新的依赖this.newDepIds=newSet();/******添加***************************/this.id=++uid;//用于批处理的uid//选项if(options){this.sync=!!options.sync;/**************************************/this.get();}...}我们还提供了一个options对象,里面保存了sync字段,表示是立即触发Watcher还是像之前一样放到队列中。然后在Watcher的update方法中,我们调用加入队列的函数。exportdefaultclassWatcher{...update(){if(this.sync){this.run();//直接运行}else{queueWatcher(this);//加入队列}}...}看看queueWatcher的实现。常量队列=[];//保存Watcher队列lethas={};//重复数据删除Watcherletwaiting=false;//是否已经加入到setTimeout队列中exportfunctionqueueWatcher(watcher){constid=watcher.id;if(has[id]==null){has[id]=true;queue.push(观察者);//加入队列//flush入队if(!waiting){//执行Watcher函数,放入setTimeout队列,只加入Waiting=true一次;setTimeout(flushSchedulerQueue,0);}}}看上面执行Watcher队列的flushSchedulerQueue函数的实现。让冲洗=假;//队列是否正在执行letindex=0;/***刷新两个队列并运行观察者。*/functionflushSchedulerQueue(){flushing=true;让观察者,id;for(index=0;index
