现代 JavaScript 框架存在的主要原因
简评:现代 JavaScript 框架的出现最主要是解决哪个问题?这篇文章很好的解释了这个问题。
我见过许多人盲目地使用像 React,Angular 或 Vue.js 这样的现代框架。这些框架提供了许多有趣的东西,通常人们会忽略这些框架存在最主要的原因,这些原因不是:
- 它们基于组件;
- 它们有一个强大的社区;
- 它们有很多第三方库;
- 它们有很多有用的第三方组件;
- 它们有浏览器插件,可以帮助调试;
- 它们适用于单页面应用程序。
这些都不是最本质的原因,最本质的原因是保持 UI 和状态同步并不容易。
UI 和 状态同步难在哪?
假如,您正在构建一个 Web 应用程序,用户可以填写他人的 email 地址来发起邀请。并且邀请列表有两种状态:
- 空状态,我们在这个状态下提示用户填写邮箱。
- 非空状态,这种状态我们需要列出出等待被邀请的用户,并且提供删除按钮。
尝试使用纯 JavaScript 实现这种功能
源码和效果可以到参考:codepen。
index.html 代码
`
Type an email address and hit enter
`
JS 代码
`class AddressList {
constructor(root) {
// state variables
this.state = []
// UI variables
this.root = root
this.form = root.querySelector('form')
this.input = this.form.querySelector('input')
this.help = this.form.querySelector('.help')
this.ul = root.querySelector('ul')
this.items = {} // id -> li element
// event handlers
this.form.addEventListener('submit', e => {
e.preventDefault()
const address = this.input.value
this.input.value = ''
this.addAddress(address)
})
this.ul.addEventListener('click', e => {
const id = e.target.getAttribute('data-delete-id')
if (!id) return // user clicked in something else
this.removeAddress(id)
})
}
addAddress(address) {
// state logic
const id = String(Date.now())
this.state = this.state.concat({ address, id })
// UI logic
this.updateHelp()
const li = document.createElement('li')
const span = document.createElement('span')
const del = document.createElement('a')
span.innerText = address
del.innerText = 'delete'
del.setAttribute('data-delete-id', id)
this.ul.appendChild(li)
li.appendChild(del)
li.appendChild(span)
this.items[id] = li
}
removeAddress(id) {
// state logic
this.state = this.state.filter(item => item.id !== id)
// UI logic
this.updateHelp()
const li = this.items[id]
this.ul.removeChild(li)
}
// utility method
updateHelp() {
if (this.state.length > 0) {
this.help.classList.add('hidden')
} else {
this.help.classList.remove('hidden')
}
}
}
const root = document.getElementById('addressList')
new AddressList(root)`
这段代码很好的说明了使用纯 JavaScript 实现一个有点小复杂的 UI 所需要的工作量。
在示例中,静态结构在 HTML 中创建,动态内容使用 JavaScript 来创建。这种方式有几个问题:
构建 UI 的 JavaScript 代码可读性不高,我们用两个不同的部分来定义 UI。我们可以使用 innerHTML来让代码更容读,但是这样效率不高,而且容易引发跨站脚本漏洞。我们也可以使用模板引擎,但是如果重新生成大的 DOM 的子节点又会遇到两个问题:效率不高,通常需要重新连接 event handler。
但这都是小问题,最主要的问题是:我们需要在状态变更的时候更新 UI。每一次状态出现变更我们都需要使用大量的代码来更新 UI。上面的例子我们更新状态是用了两行的代码,但是更新 UI 却耗费了 13 行代码(尽管这个 UI 并不复杂)。
它不仅编写起来复杂而且还很脆弱。想象一下,我们需要实现将列表于服务器同步的功能。我们需要将本地数据和服务器发来的数据进行比较。并且需要点对点的对每个变更同步到 DOM 节点中。如果这个过程中有每一步出现差错都直接导致 UI 同步失败。
因此,维护 UI 与数据同步需要编写大量繁琐,脆弱和脆弱的代码。
声明式 UI 解决方案
它是不是社区,它不是工具,也不是生态系统,也不是第三方库......
到目前为止,这些框架提供的最大的改进是实现应用状态和 UI 同步。
我们只需要定义一次 UI,不必编写为每一次动作编写 UI。相同的状态总能得到相同的 UI 输出(状态和 UI 同步,状态变更后会自动更新 UI)。
原理
有两个基本策略:
- 重新渲染整个组件: React。当组件的状态发送变化时,它会在内存中渲染一个 DOM,并和现有 DOM 进行比较。但是为了降低成本,实际上它会渲染一个虚拟 DOM,来和之前的虚拟 DOM 进行比较,然后计算更改并对真实 DOM 进行修改。
- 使用观察者来监听变化: Angular 和 Vue.js 观察你的状态变化,并且只会更新关联的 DOM 元素。
和 Web Component 比较?
很多时候人们将 React,Angular 和 Vue.js 和 Web 组件进行比较。很多人不理解这些框架提供的最大好处:保持 UI 和状态同步。而 Web 组件并不提供内容,它是一套规范,以便开发者可以自由创建可重用的元素。所以单纯使用 Web Component + 纯 JavaScript 仍然需要手动保证状态同步,要实现高效易维护的 UI 还需要使用 现代 JavaScript 框架。
自己实现
自己实现一个类似的功能,能够加深对原理的理解。我们尝试使用 虚拟DOM (而不是直接用第三方框架)实现一个类似 React 的框架,来重写刚刚的 demo。
下面是我们 Framework 的核心部分,代表所有组件的基类:
下面是基于 Component 重写的邮箱邀请的应用(借助 babel 变换来支持 JSX)这里是源码:
现在的 UI 是声明性的,而且我们没有直接使用任何框架。我们可以实现以任何方式更改状态的逻辑,并且不需要额外编写 UI 同步的代码。
原文:The deepest reason why modern JavaScript frameworks exist
现代 JavaScript 框架存在的主要原因的更多相关文章
- JS读书心得:《JavaScript框架设计》——第12章 异步处理
一.何为异步 执行任务的过程可以被分为发起和执行两个部分. 同步执行模式:任务发起后必须等待直到任务执行完成并返回结果后,才会执行下一个任务. 异步执行模式:任务发起后不等待任务执行完成,而是马上 ...
- 有了 Docker,用 JavaScript 框架开发的 Web 站点也能很好地支持网络爬虫的内容抓取
点这里 阅读目录 用 AngularJS(以及其它 JavaScript 框架)开发的 Web 站点不支持爬虫的抓取 解决方案 为什么公开我们的解决方案 实现 AngularJS 服务 结论 Pr ...
- crawler_Docker_解决用 JavaScript 框架开发的 Web 站点抓取
[转载,后续补上实践case] 有了 Docker,用 JavaScript 框架开发的 Web 站点也能很好地支持网络爬虫的内容抓取 [编者的话]Prerender 服务能够为网络爬虫提供预先渲染的 ...
- 10大支持移动“触摸操作”的JavaScript框架
摘要:移动开发行业的发展速度让人目不暇接,也在此大势之下,推出移动网站App成为开发者必经之路,如何让触屏设备 更易使用?如何让网站对触摸手势做出反应并使触摸更友好?所有这一切,皆因JavaScrip ...
- 值得认真学习的6 个 JavaScript 框架
JavaScript JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本 ...
- 2017年 JavaScript 框架回顾 -- React生态系统
前一篇文章中,我们介绍了2017年 JavaScript 框架的整体情况.我们也了解到在众多的前端框架中,目前最为庞大又在快速增长的当属 React 了,本文就来重点介绍 React 的生态系统. 首 ...
- 2017年 JavaScript 框架回顾 -- 后端框架
本文是2017年 JavaScript 框架回顾系列的最后的一篇文章,主要介绍 JavaScript 的后端框架情况. 从上图中可以看到,Express 作为用 JavaScript 编写的后端服务的 ...
- 13个可实现超棒数据可视化效果的Javascript框架
随着商业及其相关需求的发展,数据成为越来越重要的元素之一,为了更加直观和明显的展示商业潜在的趋势和内在的特性,我们需要使用图表和图形的方式来直观动态的展示数据内在秘密,在今天的这篇文章中我们推荐12款 ...
- 10个最佳的触控手式的JavaScript框架(转)
由于各种原因移动开发是一项艰难的工作,比如它是非常耗时的.充满压力的任务.最重要的是,作为一个开发人员,你必须保持更新所有最新 的技术和技巧——你必须知道所有最新的趋势,问题和解决方案等.例如跨浏览器 ...
随机推荐
- cdoj915-方老师的分身 II (长度不小于k的最短路)【spfa】
http://acm.uestc.edu.cn/#/problem/show/915 方老师的分身 II Time Limit: 10000/5000MS (Java/Others) Memo ...
- iOS中NSDate常用转换操作整合
//当前时间格式化, 例:YYYY-MM-dd-EEEE-HH:mm:ss + (NSString *)getCurrentDataWithDateFormate:(NSString *)format ...
- 解决"authentication token manipulation error"
昨天安装是Ubuntu Server. 配置好了几个软件后就忘记继续了...今天打开,居然忘记了密码...真是的.. 后来还是要改了. 不想重新弄什么的了..百度了下怎么改密码...然后就有一篇 ...
- Oracle VM VirtualBox 部署CS devcloud2 开发环境
Setting up (VirtualBox) 1. Get the new DevCloud 2.0 virtual appliance. The new image was created usi ...
- etherboot无盘启动
2001.10.30 吴峰光 本站提供对无盘启动的支持.本文就此作一简单介绍. 一.概述 无盘启动,更确切的说是网络启动,可算是最为轻松和简便的启动方式了. 目前还很少有人了解它,因为目前的软硬件条件 ...
- 用Redis解决互联网项目的数据读取难点
Redis在很多方面与其他数据库解决方案不同:它使用内存提供主存储支持,而仅使用硬盘做持久性的存储:它的数据模型非常独特,用的是单线程.另一个大区别在于,你可以在开发环境中使用Redis的功能,但却不 ...
- code3731 寻找道路
将图反向,从终点spfa,把和终点没有联系的点找出来, 把它们和它们所连接的所有点删去(反向图) 然后再一遍spfa,输出最短路即可 代码: #include<iostream> #inc ...
- 第一次用FontLad~
FontLad 是一款制作字体的工具 使用流程: 1. 下载.安装软件FontLab Studio2. File->New菜单,创建一个工程文件,会自动创建一个ASCII码表对应的字体表3. ...
- transition与animation的区别
transition需要事件触发,animation可以直接自动触发,而且功能上更为强大,包括可以设置不同时间段的动画规则,还有状态的控制,事件等等.
- [GO]使用bufio的文件读取方式
package main import ( "os" "fmt" "bufio" "io" ) func ReadFil ...