1.大公司很少用vue的源码e源原因
2.vue2.x中的数据异步更新和nextTick方法解析
大公司很少用vue的原因
如果他告诉你只会Vue,你一定要小心了,码揭秘原因:
1、源码e源如果他只会Vue,码揭秘那他就真的源码e源只会这一个东西了。但是码揭秘mvc系统源码免费,如果他同时还会Angular或者其它一些前端框架,源码e源一般就意味着这个人的码揭秘性价比会非常高。首先,源码e源如果他会Angular,码揭秘那么降低一个维度去写Vue是源码e源完全没有问题的,毕竟Vue里面大部分内容都是码揭秘从AngularJS 1.x(而不是新版本Angular)里面抄出来的。其次,源码e源大量的码揭秘Angular开发者都同时会一种或几种后端语言,如Java和C#,源码e源这就意味着你用同样的工钱招到了一个能干更多事情的人。
2、只会Vue的人缺乏学习能力,你招到的可能只是个“拷贝工程师”。你经常看到这种小白会吐槽Type是他人生道路上的障碍,而实际上Type的大部分语法都来自于ES6(还有ES7),如果这个人连Type都说难,只能说明一件事情:他根本就没去学ES6和ES7(最近ES8也出来了)。暴力猴插件源码实际上Type的受欢迎程度远远超越你们的想象,包括目前最火的前端开发工具VS Code本身也是用Type开发的,底层是Electron。从另一个角度看,iOS上的开发语言已经演进到了Swift,Android上也开始使用新语言Kotlin了,随着计算机技术的加速发展,各种编程语言还会加速演进。所以,Type不是他人生道路上的障碍,他最大的障碍是他自己。
3、坐井观天。一般来说,能同时使用多种框架的开发者,心里对各种技术都有自己独到的理解。他们知道整个互联网的发展史、知道Java语言是怎么一步一步发展到今天的、知道ECMA标准是怎么一回事、知道各种前端框架在设计思想上的异同,在他的心里有一个非常宏观的理解。
4、青春博客PHP源码糟糕的英文水平。有很多人告诉过我,他们之所以用上了Vue,是以为中文文档写得好(这一点我赞同)。反过来说明,这帮人英文水平比较糟糕。一直以来,计算机技术的发源地都是硅谷,到今天依然如此。硅谷一直在创造各种各样的新技术、新思想,而这些东西最初都是英文版的。一本书从英文版出来,到第一本中文版面市,经常要延迟6个月以上的时间,如果你招聘的开发者连阅读英文技术文档都有困难,你们公司将会永远掌握二手资料。
5、糟糕的团队协作。从之前文章下面的评论能看出来,只会Vue的小白对他们所用的框架充满着宗教般的狂热,只准他们出来黑别人,模糊故障树源码别人如果胆敢出来哪怕是澄清一下,马上就像刺猬一样炸毛。这种人会把你的团队搅得一团糟,连道理都没法讲。反过来也是成立的,对于正在跳槽或者打算找工作的开发者,当你去一家公司面试的时候,也要长个心眼儿,你一定要问一问,他们公司正在使用(或者曾经用过)哪些前端框架。如果这家公司告诉你,他们就只会用Vue,你要小心了,因为:
6、这种公司一定充斥着各种前端小白,这些人没用过其它任何框架,甚至连快速学习一门新的编程语言都有困难,但是这不妨碍他们操起键盘出来胡说八道。你去了之后可能要给他们提供保姆一样的服务,甚至还要教他们如何搭建Node环境。
7、这种公司的Python遍历新闻源码技术负责人很可能是个小白,至少是个盲目的跟风者。他自己是不会去研究技术的,听别人忽悠就好了。你去帮这种人做事,注定是不断填坑的命运。
8、这种公司一定没有规范的开发流程,可能连CI系统都没有。以Vue为例,框架和工具都没有对集成测试做任何支持,所以这种公司一定从来不做集成测试的,否则他们老早就会发现这个问题了。你去这样的公司,除了让已经学会的技能不断退化还能学到什么新东西?
9、这种公司没有长远打算。在技术选型上的短视就意味着管理层本身是短视的,他们从来没有长远的打算,做完一个东西收一波钱完事,至于用什么技术更好,一点都不重要。在这样的公司做技术?别逗了。他们之所以要你去,只是想让你随意搭建点儿什么东西,把客户的钱忽悠到手而已。
vue2.x中的数据异步更新和nextTick方法解析
前言
众所周知,vue中的更新时异步的,比如this.msg=xxx,你看起来他是立马更新了,其实并没有。它会异步执行,接下来就来看看怎么实现的吧。
先上图首先从数据改动开始说起调用this.msg=xxx数据发生变更
在数据初始化阶段已经收集了依赖的watcher到dep中,执行dep.notify通知watcehr变更
notify方法遍历调用所有以来的watcher的update方法,把当前watcher实例放入queueWatcher函数中执行,接下来就是异步更新的关键了,看代码
queueWatcher函数代码在src\core\observer\scheduler.js主要作用:把当前watcher实例添加到一个queue中
exportfunctionqueueWatcher(watcher:Watcher){ //拿到watcher的唯一标识constid=watcher.id//无论有多少数据更新,相同的watcher只被压入一次//我理解这就是为什么在一次操作中,多次更改了变量的值,但是只进行了一次页面更新的原因,//同一变量依赖它的watcher是一定的,所以已经存在了就不再放进watcher队列中了,也不会走后面的逻辑if(has[id]==null){ //缓存当前的watcher的标识,用于判断是否重复has[id]=true//如果当前不是刷新状态,直接入队if(!flushing){ queue.push(watcher)}else{ //ifalreadyflushing,splicethewatcherbasedonitsid//ifalreadypastitsid,itwillberunnextimmediately.//此处能走到这儿,说明flushSchedulerQueue函数被执行了watcher队列已经正在开始被更新了,//并且在执行某个watcher.run方法的时候又触发的数据响应式更新,重新触发了queueWatcher//因为在执行的时候回有一个给watcher排序的操作,所以,当watcher正在更新时已经是排好顺序了的,此时需要插入到特定的位置,保持watcher队列依然是保持顺序的leti=queue.length-1while(i>index&&queue[i].id>watcher.id){ i--}queue.splice(i+1,0,watcher)}//queuetheflush//waiting表示当前的flushSchedulerQueue还没有被执行,因为还没有重置状态,waiting仍然为true//所以waiting的意义就是表明是否执行了flushSchedulerQueue,if(!waiting){ waiting=true//直接同步刷新队列if(process.env.NODE_ENV!=='production'&&!config.async){ //同步执行flushSchedulerQueue()return}//把更新队列函数放到异步队列中nextTick(flushSchedulerQueue)}}}flushSchedulerQueue代码在相同目录下//主要作用:遍历执行每一个watcher的run方法,进而实现数据和视图的更新,并在执行完所有的方法之后,重置状态,表示正在刷新队列的flushing,表示watcher是否存在的has,表示是否需要执行nexttick的waiting
functionflushSchedulerQueue(){ //当方法被执行时,设置为正在刷新状态,以示可以继续执行nextTick方法flushing=true//把队列中的watcher排个序,/***排序的作用:(此句照搬照抄而来)*1.保证父组件的watcher比子组件的watcher先更新,因为父组件总是先被创建,子组件后被创建*2.组件用户的watcher在其渲染watcher之前执行。*3.如果一个组件在其父组件执行期间被销毁了,会跳过该子组件。*/queue.sort((a,b)=>a.id-b.id)//中间略去若干代码...//遍历queue中存的所有的watcher,执行run方法更新for(index=0;index<queue.length;index++){ watcher=queue[index]watcher.run()}//因为queue是在一个闭包中,所以当遍历执行完毕了,就把队列清空queue.length=0;//has是判断当前watcher是否重复,作为是否把watcher放进queue的依据//此时已经执行完了queue中的所有watcher了,之前已经执行过的watcher如果发生了变更,可以重新加入了has={ }//waiting是判断是否执行nextTick的标识,当前的刷新队列已经执行完毕了,说以,可以设置为false了,执行下一轮的的添加异步事件队列的方法//flushing是判断是否当前异步事件正在执行的标志,当前更新完毕,作为判断watcher入队的形式waiting=flushing=false}nextTick方法源码src\core\util\next-tick.js
exportfunctionnextTick(cb?:Function,ctx?:Object){ let_resolve//把执行更新操作之后的回调函数添加到队列里//用trycatch包装一下传进来的函数,避免使用$nextTick时,传入的回调函数出错能够及时的捕获到//只要执行了nextTick函数,就把回调函数添加到回调列表里//这里的cb回调函数就是flushSchedulerQueue函数,里面执行了queue中存放的所有的watcher.run方法callbacks.push(()=>{ if(cb){ try{ cb.call(ctx)}catch(e){ handleError(e,ctx,'nextTick')}}elseif(_resolve){ _resolve(ctx)}})//通过pending来判断是否需要向任务队列中添加任务//如果上一个清空回调列表的当flushCallbacks函数还在任务队列中,就不往任务队列中添加//第一次执行时,就默认就添加一个进任务队列,一旦添加进任务队列,就表明暂时不在需要往任务队列中添加flush函数//当执行了上一个flushCallbacks函数的时候,pending修改为false,表明可以重新添加一个清空回调列表的flush函数到任务队列了if(!pending){ pending=true//这里是调用清空callbacks数组中方法,并执行的函数,timerFunc()}//$flow-disable-line//判断当前环境是否支持promise,如果支持的话,可以返回一个期约对象,if(!cb&&typeofPromise!=='undefined'){ returnnewPromise(resolve=>{ _resolve=resolve})}}timerFunc()方法,主要是做一些降级操作,实现异步的关键
timerFunc=()=>{ Promise.resolve().then(flushCallbacks)}//如果当前环境不支持的话,会进行一定的降级操作,直到最后,用宏任务settimeout来处理看看flushCallbacks,任务就是执行了所有的callbacks函数
functionflushCallbacks(){ //如果开始执行了flushCallbacks说明,当前的异步任务已经为空了,如果此时再nextTick方法会添加新的任务进去了pending=false//拷贝一份callbacks中的所有回调函数,用于执行constcopies=callbacks.slice(0)//随即删除所有callbackscallbacks.length=0//当微任务队列中的flushCallbacks添加到执行栈中了,就执行callbacks中的所有的函数//也就是调用执行每一个flushSchedulerQueue函数,然后遍历执行每一个函数for(leti=0;i<copies.length;i++){ copies[i]()}}基本关键变量的作用waiting:变量,作为是否执行nextTick,添加flushSchedulerQueue方法的关键,标志着callbacks中是否有flushSchedulerQueue方法,比如同一个变量的改变,可能会影响多个watcher,因为执行flushSchedulerQueue是异步的,遍历dep.update先把所有的watcher都放入到queue中,也才只执行了一次nextTick,callbacks中也只有一个方法。虽然当第一次方如watcher时就会执行nexttick把flushSchedulerQueue方法放入callbacks中,看起来好像已经要执行了,但是因为queue是闭包变量,所以,后续的变量仍然可以添加queue中,
flushing::表示是否正在执行flushSchedulerQueue方法,如果是正在执行更新方法的话,对向已经排好序的watcher队列中添加新的watcher,需要把新watcher插入到排好序的指定的位置,这也就是为什么遍历watdher那块儿会直接使用queue.length的原因,这个长度会发生变化。
pending::pending是决定是否把更新callbacks数组的方法放入异步队列的关键,保证了异步队列中只有一个清空callbacks的任务,也就解释了,连续手动执行多个$nextTick方法不会立即执行,也还是会把他们的回调放入callbacks中,然后等到任务都执行完毕了,一下把所有的回调函数都执行掉。
参考
vue源码
/post/