1。写在上一篇文章中,本文将带领大家走进《Vue.js设计与实现》所描绘的宇宙,开启一场探索框架设计思想的旅程。2.取舍的艺术在框架设计中无处不在。作者在文章中写道“取舍的艺术在框架设计中无处不在”。的确,在选择设计模式和技术时,我们会综合考虑性能和开发效率,权衡各种因素,以获得尽可能完美的框架。框架由各个模块组成,这些模块既相互关联又相互独立。为了实现当前的功能,还必须考虑后续的模块拆分和扩展。作为框架设计者,需要站在全局的角度去思考和设计,需要对整体的设计思路有清晰的把控。实现细节是设计时不需要过多关注的一个角度。不要被山上的雾层所限制。毕竟只是整个框架的冰山一角。在Vue框架的设计中,这种权衡可能最能体现“命令式与声明式”、“编译时与运行时”等之间的权衡,需要了解彼此之间的差异并学习两者的优点。3.命令式和声明式如您所知,计算机编程范式分为三种类型:命令式编程、声明式编程和函数式编程。命令式编程:关注计算机执行的步骤,即告诉计算机先做什么,然后一步步做什么。声明式编程:以数据结构的形式表达程序执行的逻辑。它的主要思想是告诉计算机做什么,而不是指定如何做。函数式编程:与声明式编程相关联,侧重于做什么而不是如何做。但是函数式编程并不局限于声明式编程。势在必行对于前端开发从业者来说,JQuery框架并不陌生。它实际上是最经典的命令式框架设计。它着重于计算机执行的步骤,即过程。命令式编程其实是为计算机编写的,让我们的自然语言可以和代码一一对应,更符合我们做事的逻辑。$("#app")//获取id为app.text("hellopingping")的label元素//设置label的文本内容.on("click",()=>console.log("helloonechuan"));//id为app的笔记的绑定事件相当于原生js代码:constdiv=document.querySelector("#app");div.innerText="hellopingping";div.addEventListener("click",()=>console.log("helloonechuan"))声明式和声明式更注重执行结果,具体的执行过程不是用户关心的,也大大降低了认知成本,专注于表面逻辑,提高使用效率。事实上,Vue.js的设计并不是简单地使用纯命令式或声明式编程,而是结合了两者的优点。内部实现使用命令式告诉计算机如何运行,对外暴露的API使用声明式编程,可以让用户用人性化的方式理解结果。
console.log('helloonechuan')">hellopingping
性能和可维护性在《编译原理》一书中,我了解到命令式代码比声明式代码执行得更好,因为声明式代码需要编译成计算机可以理解的命令式代码。然而,声明式代码更像是一种人类可以理解的人类语言,它在降低代码维护成本的同时尽可能少地牺牲性能。Vue.js框架结合了两者的优点,封装了命令式代码,为用户提供更易于维护的声明式代码。4.对于realDOM和virtualDOM之间声明式代码的更新性能消耗:声明式代码的更新性能消耗=找出差异的性能消耗+直接修改的性能消耗,如果我们找到可以使的性能消耗找到差异最小化算法,那么声明式代码的性能消耗可以无限接近命令式代码的性能消耗。我们从创建页面和更新页面两个方面分析真实DOM和虚拟DOM操作的性能消耗:状态虚拟DOM(纯JS创建VNODE)真实DOM(渲染HTML字符串)创建页面,创建所有DOM对象,创建所有DOM对象更新页面必要的DOM更新-销毁所有旧DOM,创建所有新DOM关于性能:真实DOM<虚拟DOM<原生JS。这里简单总结一下,后续文章会有更详细的数据分析。5、编译时和运行时在设计框架时,还要考虑是选择:纯运行时、纯编译时,还是运行时+编译时。这需要结合你期望的框架的特性来做出合适的决定。运行时所谓运行时,就是计算机在不需要经过额外的处理就可以达到我们期望的结果时运行的代码。比如我们需要将提供的树状结构的数据对象渲染成dom树,那么我们就需要设计一个Render函数直接渲染,这样就可以得到我们想要的结果:constobj={tag:"div",children:[{tag:"span",children:"helloworld"}]}Render(obj,document.body)functionRender(obj,root){constel=document.createElement(obj.tag);if(typeofobj.children==="string"){consttext=document.createTextNode(obj.children);el.appendChild(text)}elseif(obj.children){//如果是数组,则递归调用render,以el为根参数obj.children.forEach(child=>Render(child,el))}//最后将元素添加到根元素root.appendChild(el)}浏览器显示如下:然后编译时,编译是一种将高级语言转换为低级语言的转换技术,Vue.js通过编译将HTML标签转化为树状结构的数据对象。这样,我们就需要编写一个Compiler函数,通过编译将HTML标签转化为树状结构的数据对象。如下:consthtml=`
helloworld
`constobj=compoler(html)Render(obj,document.body)这样:
hellopingping
编译成:constobj={tag:'div',children:[{tag:'span',children:'helloworld'}]}结合Render函数进行渲染,所以我们可以初步设计出一个运行时+编译时的框架。运行时+编译时Vue.js中所谓的运行时+编译时框架,其实是指:支持运行时:用户可以直接提供树状结构的数据对象,无需编译;支持编译时:用户可以将提供的HTML字符串编译成树状结构的数据对象,然后交给运行时处理。为什么Vue.js被设计为运行时+编译时框架?这个设计也是开源团队做出权衡的结果。用户提供的内容无法在运行时分析,添加编译后可以对用户内容进行分析编译。这些用户内容的信息在编译时被提取出来,然后通过Render函数渲染出来。当然,当框架设计为纯编译时,用户内容可以直接分析编译成可执行的JS代码,在保证性能的同时牺牲了框架的灵活性和可维护性。对于用户来说,内容必须在使用前编译。在这方面,Vue.js的设计是综合考虑的,只采用运行时+编译时的框架设计。在保留运行时灵活性的同时,尽可能不牺牲性能。6.写在这篇文章的最后,我了解了开源团队在命令式和声明式、真实DOM和虚拟DOM、运行时和编译时间之间的权衡,在提供最佳用户体验的同时将性能损失降到最低。可维护性、灵活性。