简评:现代 JavaScript 框架的出现最主要是解决哪个问题?这篇文章很好的解释了这个问题。

我见过许多人盲目地使用像 React,Angular 或 Vue.js 这样的现代框架。这些框架提供了许多有趣的东西,通常人们会忽略这些框架存在最主要的原因,这些原因不是:

  • 它们基于组件;
  • 它们有一个强大的社区;
  • 它们有很多第三方库;
  • 它们有很多有用的第三方组件;
  • 它们有浏览器插件,可以帮助调试;
  • 它们适用于单页面应用程序。

这些都不是最本质的原因,最本质的原因是保持 UI 和状态同步并不容易。

UI 和 状态同步难在哪?

假如,您正在构建一个 Web 应用程序,用户可以填写他人的 email 地址来发起邀请。并且邀请列表有两种状态:

  1. 空状态,我们在这个状态下提示用户填写邮箱。
  2. 非空状态,这种状态我们需要列出出等待被邀请的用户,并且提供删除按钮。

尝试使用纯 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 框架存在的主要原因的更多相关文章

  1. JS读书心得:《JavaScript框架设计》——第12章 异步处理

    一.何为异步   执行任务的过程可以被分为发起和执行两个部分. 同步执行模式:任务发起后必须等待直到任务执行完成并返回结果后,才会执行下一个任务. 异步执行模式:任务发起后不等待任务执行完成,而是马上 ...

  2. 有了 Docker,用 JavaScript 框架开发的 Web 站点也能很好地支持网络爬虫的内容抓取

    点这里 阅读目录 用 AngularJS(以及其它 JavaScript 框架)开发的 Web 站点不支持爬虫的抓取 解决方案 为什么公开我们的解决方案 实现 AngularJS 服务 结论   Pr ...

  3. crawler_Docker_解决用 JavaScript 框架开发的 Web 站点抓取

    [转载,后续补上实践case] 有了 Docker,用 JavaScript 框架开发的 Web 站点也能很好地支持网络爬虫的内容抓取 [编者的话]Prerender 服务能够为网络爬虫提供预先渲染的 ...

  4. 10大支持移动“触摸操作”的JavaScript框架

    摘要:移动开发行业的发展速度让人目不暇接,也在此大势之下,推出移动网站App成为开发者必经之路,如何让触屏设备 更易使用?如何让网站对触摸手势做出反应并使触摸更友好?所有这一切,皆因JavaScrip ...

  5. 值得认真学习的6 个 JavaScript 框架

    JavaScript   JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本 ...

  6. 2017年 JavaScript 框架回顾 -- React生态系统

    前一篇文章中,我们介绍了2017年 JavaScript 框架的整体情况.我们也了解到在众多的前端框架中,目前最为庞大又在快速增长的当属 React 了,本文就来重点介绍 React 的生态系统. 首 ...

  7. 2017年 JavaScript 框架回顾 -- 后端框架

    本文是2017年 JavaScript 框架回顾系列的最后的一篇文章,主要介绍 JavaScript 的后端框架情况. 从上图中可以看到,Express 作为用 JavaScript 编写的后端服务的 ...

  8. 13个可实现超棒数据可视化效果的Javascript框架

    随着商业及其相关需求的发展,数据成为越来越重要的元素之一,为了更加直观和明显的展示商业潜在的趋势和内在的特性,我们需要使用图表和图形的方式来直观动态的展示数据内在秘密,在今天的这篇文章中我们推荐12款 ...

  9. 10个最佳的触控手式的JavaScript框架(转)

    由于各种原因移动开发是一项艰难的工作,比如它是非常耗时的.充满压力的任务.最重要的是,作为一个开发人员,你必须保持更新所有最新 的技术和技巧——你必须知道所有最新的趋势,问题和解决方案等.例如跨浏览器 ...

随机推荐

  1. validator 参数校验的常用注解

    @AssertFalse Boolean,boolean 验证注解的元素值是false @AssertTrue Boolean,boolean 验证注解的元素值是true @NotNull 任意类型 ...

  2. Ros学习——Cmakelists.txt文件解读

    1.过程 .Required CMake Version (cmake_minimum_required) //CMake 需要的版本 .Package Name (project()) //#定义工 ...

  3. linux ifconfig显示 command not found

    本人装的是centos7 想看下网络配置 结果显示如图: 正常情况下 ifconfig  是在超级管理员 的所属的目录 sbin/下的命令 现在来查看该目录下. 没有找到,别急 用 yum  sear ...

  4. Python下Pip的安装【get-pip】

    1.下载 下载https://bootstrap.pypa.io/get-pip.py 如果不能下载,可下载:http://files.cnblogs.com/files/zhangzhiming/g ...

  5. [C++] Template Function _ Any number of parameters

    Template Function _ Any number of parameters #include<iostream> #include<cstdarg> using ...

  6. [JAVA] 冻结Excel的第一行或第一列

    可以按照如下设置创建冻结窗口. sheet.createFreezePane( 3, 2, 3, 2 ); 前两个参数是你要用来拆分的列数和行数.后两个参数是下面窗口的可见象限,其中第三个参数是右边区 ...

  7. [Training Video - 7] [Database connection] Various databases which are supported, Drivers for database connection, SQL Groovy API

    Various databases which are supported Drivers for database connection groovy.sql.Sql package SoapUI怎 ...

  8. html 图片拖动不出来的脚本

    function imgdragstart() { return false; } $(function(){ for (i in document.images) document.images[i ...

  9. jenkins持续集成之Global Tool Configuration的配置

    Global Tool Configuration的配置过程: 1.点击系统管理2.点击 Global Tool Configuration3.必须配置: jdk git ant maven 1.点击 ...

  10. Html创建表单

    echo Html::beginForm(['/site/logout'], 'post'); echo Html::submitButton(Yii::t('app', 'logout'), ['c ...