异步编制程序真的好吧,不契合复杂的前端项目
分类:前端技术

缘何 ReactJS 不切合复杂的前端项目?

2016/08/17 · JavaScript · 15 评论 · React, ReactJS, 前端

本文小编: 伯乐在线 - ThoughtWorks 。未经小编许可,幸免转发!
迎接参预伯乐在线 专辑作者。

《More than React》种类的稿子会一齐分为五篇。本文是首先篇,介绍用ReactJS开拓时遇上的各个难题。前边四篇作品的每一篇将会独家详细商量在那之中一个主题材料,以至Binding.scala怎么样消除那么些标题。

《More than React》种类的小说会一齐分为五篇。本文是率先篇,介绍用ReactJS开拓时遇上的各类难题。前面四篇随笔的每生机勃勃篇将会独家详细座谈此中一个标题,以致Binding.scala怎么着消除那些难题。

文/杨博

HTML也足以静态编写翻译?

2016/11/30 · HTML5 · 1 评论 · binding.scala, React, 前端

本文小编: 伯乐在线 - ThoughtWorks 。未经作者许可,幸免转发!
接待参预伯乐在线 专辑编辑者。

More than React类别随笔:

《More than React(一卡塔尔为何ReactJS不切合复杂的前端项目?》

《More than React(二卡塔 尔(阿拉伯语:قطر‎React.Component损伤了复用性?》

《More than React(三)虚拟DOM已死?》

《More than React(四卡塔尔国HTML也足以静态编写翻译?》


《More than React》体系的上生龙活虎篇作品《虚拟DOM已死?》正如了Binding.scala和其他框架的渲染机制。本篇作品中校介绍Binding.scala中的XHTML语法。

背景介绍

二〇一八年 4 月,作者先是次在某些顾客的品种中接触到ReactJS 。

自己开采ReactJS要比本人早先用过的AngularJS简单非常多,它提供了响应式的多寡绑定成效,把数量映射到网页上,使自个儿得以轻巧完毕相互之间简单的网址。

唯独,随着笔者更深切的应用ReactJS,小编开掘用ReactJS编写人机联作复杂的网页很困难。 作者期望有风流罗曼蒂克种方式,可以像ReactJS同样简单消除轻易难题。别的,还要能轻松排除复杂难点。

于是乎作者把ReactJS用Scala重新写了四个。代码量从近四万行降至了生机勃勃千多行。

用这么些框架实现的TodoMVC应用,只用了154行代码。而用ReactJS完成平等效能的TodoMVC,需要488行代码。

下图是用Binding.scala完成的TodoMVC应用。

图片 1

本条框架就是Binding.scala。

背景介绍

二〇一八年 4 月,作者第叁次在有个别顾客的连串中接触到ReactJS 。

自个儿意识ReactJS要比小编原先用过的AngularJS轻松超多,它提供了响应式的多少绑定成效,把多少映射到网页上,使作者得以轻巧完成相互作用轻松的网址。

不过,随着作者越来越深入的使用ReactJS,作者意识用ReactJS编写交互作用复杂的网页十分不方便。
自身期望有意气风发种办法,能够像ReactJS同样轻松化解轻巧难点。其它,还要能大致灭绝复杂难点。

于是本身把ReactJS用Scala重新写了二个。代码量从近六万行降低到了生机勃勃千多行。

用那几个框架完结的TodoMVC应用,只用了154行代码。而用ReactJS实现均等效果的TodoMVC,需要488行代码。

下图是用Binding.scala达成的TodoMVC应用。

那一个框架正是Binding.scala。

本文首发于InfoQ:http://www.infoq.com/cn/articles/more-than-react-part05

任何前端框架的主题材料

难点生龙活虎:ReactJS组件难以在错综相连人机联作页面中复用

ReactJS中的最小复用单位是组件。ReactJS的零器件比AngularJS的Controller和View 要轻量些。 每个组件只要求前端开采者提供四个 render 函数,把 propsstate 映射成网页成分。

像这种类型的轻量级组件在渲染简单静态页面时很好用, 可是如若页面有互相,就务须在组件间传递回调函数来处监护人件。

自个儿就要《More than React(二卡塔 尔(阿拉伯语:قطر‎组件对复用性有毒?》中用原生DHTML API、ReactJS和Binding.scala完成同二个索要复用的页面,介绍Binding.scala怎么样轻易完结、轻易复用复杂的相互逻辑。

主题素材风华正茂:ReactJS组件难以在纷纷交互作用页面中复用

ReactJS中的最小复用单位是组件。ReactJS的机件比AngularJS的Controller和View 要轻量些。
各种组件只必要前端开采者提供叁个 render 函数,把 propsstate 映射成网页成分。

那样的轻量级组件在渲染简单静态页面时很好用,
唯唯大器晚成旦页面有相互,就亟须在组件间传递回调函数来处总管件。

自个儿将要《More than React(二卡塔尔国组件对复用性有毒?》中用原生DHTML API、ReactJS和Binding.scala完成同二个内需复用的页面,介绍Binding.scala怎样简单达成、简单复用复杂的并行逻辑。

《More than React》体系的上后生可畏篇小说《HTML也能够编译?》介绍了 Binding.scala 怎么着在渲染 HTML 时静态检查语法错误和语义错误,进而防止 bug ,写出更健康的代码。本篇小说将研商Binding.scala和任何前端框架怎样向服务器发送央浼并在页面呈现。

对HTML的不尽援救

以前我们接纳此外前端框架,比方Cycle.js 、Widok、ScalaTags时,由于框架不协理HTML语法,前端程序员被迫浪费大批量时辰,手动把HTML改写成代码,然后逐步调试。

不怕是支持HTML语法的框架,例如ReactJS,协理景况也很四分五裂。

比方说,在ReactJS中,你不能如此写:

JavaScript

class BrokenReactComponent extends React.Component { render() { return ( <ol> <li class="unsupported-class">不支持 class 属性</li> <li style="background-color: red">不支持 style 属性</li> <li> <input type="checkbox" id="unsupported-for"/> <label for="unsupported-for">不支持 for 属性</label> </li> </ol> ); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class BrokenReactComponent extends React.Component {
  render() {
    return (
      <ol>
        <li class="unsupported-class">不支持 class 属性</li>
        <li style="background-color: red">不支持 style 属性</li>
        <li>
          <input type="checkbox" id="unsupported-for"/>
          <label for="unsupported-for">不支持 for 属性</label>
        </li>
      </ol>
    );
  }
}

前边三个程序员必须手动把 classfor 属性替换到 classNamehtmlFor,还要把内联的 style 样式从CSS语法改成JSON语法,代码技术运作:

JavaScript

class WorkaroundReactComponent extends React.Component { render() { return ( <ol> <li className="workaround-class">被迫把 class 改成 className</li> <li style={{ backgroundColor: "red" }}>被迫把体制表改成 JSON</li> <li> <input type="checkbox" id="workaround-for"/> <label htmlFor="workaround-for">被迫把 for 改成 htmlFor</label> </li> </ol> ); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class WorkaroundReactComponent extends React.Component {
  render() {
    return (
      <ol>
        <li className="workaround-class">被迫把 class 改成 className</li>
        <li style={{ backgroundColor: "red" }}>被迫把样式表改成 JSON</li>
        <li>
          <input type="checkbox" id="workaround-for"/>
          <label htmlFor="workaround-for">被迫把 for 改成 htmlFor</label>
        </li>
      </ol>
    );
  }
}

这种开采格局下,前端程序员就算能够把HTML原型复制粘贴到代码中,但还索要大批量改建技能实际运作。比Cycle.js、Widok也许ScalaTags省穿梭太多事。

难点二:ReactJS的捏造DOM 算法又慢又不准

ReactJS的页面渲染算法是编造DOM差量算法。

开采者须要提供 render 函数,根据 propsstate 生成设想 DOM。 然后 ReactJS 框架依照 render 重临的设想 DOM 创立相仿布局的老实 DOM.

每当 state 改正时,ReacJS 框架重新调用 render 函数,获取新的假造 DOM 。 然后,框架会相比较上次生成的杜撰 DOM 和新的虚构 DOM 有啥样差别,然后把差距应用到实际DOM上。

如此做有两大劣势:

  1. 每次 state 更改,render 函数都要生成完全的假造 DOM. 哪怕 state 改换非常的小,render函数也会完好总计二回。若是 render 函数很复杂,这一个进度就白白浪费了重重思考能源。
  2. ReactJS框架相比较设想DOM差距的历程,既慢又易于失误。譬喻,借使你想要在某些 <ul>列表的最上端插入风度翩翩项 <li> ,那么ReactJS框架会误认为你改改了 <ul> 的每意气风发项 <li>,然后在尾巴部分插入了多个 <li>

那是因为 ReactJS收到的新旧五个设想DOM之间相互独立,ReactJS并不知道数据源产生了怎样操作,只好依照新旧四个虚构DOM来猜测内需施行的操作。 自动的猜想算法既不许又慢,必定要前端开垦者手动提供 key 属性、shouldComponentUpdate 方法、componentDidUpdate 方法或然 componentWillUpdate 等方法才具扶助 ReactJS 框架猜对。

自己将要《More than React(三卡塔尔设想DOM已死?》中相比较ReactJS、AngularJS和Binding.scala渲染机制,介绍简单质量高的Binding.scala准确数据绑定机制。

主题素材二:ReactJS的伪造DOM 算法又慢又不许

ReactJS的页面渲染算法是假造DOM差量算法。

开辟者须要提供 render 函数,根据 propsstate 生成虚构 DOM。
下一场 ReactJS 框架依照 render 重返的虚构 DOM 创造相像构造的真人真事 DOM.

每当 state 改正时,ReacJS 框架重新调用 render 函数,获取新的假造 DOM 。
然后,框架会比较上次生成的诬捏 DOM 和新的设想 DOM 有何分裂,然后把差距应用到真正DOM上。

如此做有两大破绽:

  1. 每次 state 更改,render 函数都要生成完全的杜撰 DOM. 哪怕 state 更换相当的小,render函数也会完全总括一回。要是 render 函数很复杂,这些进度就白白浪费了重重划算财富。
  2. ReactJS框架比较虚构DOM差别的进度,既慢又便于出错。比如,借令你想要在某些 <ul> 列表的最上端插入风流浪漫项 <li> ,那么ReactJS框架会误感觉你改改了 <ul> 的每风流倜傥项 <li>,然后在尾巴部分插入了叁个 <li>

那是因为 ReactJS收到的新旧多少个设想DOM之间互相独立,ReactJS并不知道数据源发生了怎么着操作,只好依据新旧四个虚构DOM来猜测亟需奉行的操作。
机关的推测算法既不许又慢,必必要前端开采者手动提供 key 属性、shouldComponentUpdate 方法、componentDidUpdate 方法还是 componentWillUpdate 等情势技能支援 ReactJS 框架猜对。

自己就要《More than React(三卡塔 尔(阿拉伯语:قطر‎虚构DOM已死?》中相比ReactJS、AngularJS和Binding.scala渲染机制,介绍简单品质高的Binding.scala正确数据绑定机制。

在过去的前端开荒中,向服务器乞请数据须要选拔异步编程才能。异步编制程序的定义非常轻巧,指在拓展I/O 操作时,不封堵当前实施流,而经过回调函数管理 I/O 的结果。不幸的是,那几个概念即使简易,但用起来很麻烦,如果错用会导致 bug 丛生,就算谨小慎微的管理种种异步事件,也会促成程序变得复杂、更难保证。

不协作原生DOM操作

除此以外,ReactJS等片段前端框架,会生成设想DOM。设想DOM不能合营浏览器原生的DOM API ,招致和jQuery、D3等别的库同盟时千难万险。譬喻ReactJS更新DOM对象时平常会损坏掉jQuery控件。

Reddit洋美国人探究了那么些标题。他们不曾艺术,只好弃用jQuery。笔者司的某顾客在用了ReactJS后也被迫用ReactJS重写了大气jQeury控件。

标题三:ReactJS的HTML模板功能既不完善、也不康健

ReactJS支持用JSX编写HTML模板。

答辩上,前端程序员只要把静态HTML原型复制到JSX源文件中, 扩充一些变量替换代码, 就会退换成动态页面。 理论上这种做法要比Cycle.js、Widok、ScalaTags等框架更切合复用设计员提供的HTML原型。

噩运的是,ReactJS对HTML的支持七零八落。开荒者必得手动把classfor天性替换来classNamehtmlFor,还要把内联的style体制从CSS语法改成JSON语法,代码工夫运作。 这种开采格局下,前端技术员即便可以把HTML原型复制粘贴到代码中,但还亟需多量改建技术实际运营。 比Cycle.js、Widok、或许、ScalaTags省屡次太多事。

而外,ReactJS还提供了propTypes建制校验虚构DOM的合法性。 可是,这一编写制定也漏洞超多。 就算内定了propTypes,ReactJS也不能够在编写翻译前提前发掘错误。只有测量检验覆盖率超高的连串时手艺在种种组件使用其余零零部件时实行校验。 就算测量试验覆盖率相当的高,propTypes长期以来不能检查评定出拼错的属性名,尽管您把onClick写成了onclick, ReactJS就不会报错,往往变成开辟者额外花销大批量时日排查三个很简单的bug。

自家将要《More than React(四卡塔 尔(英语:State of Qatar)HTML也足以编写翻译?》中比较ReactJS和Binding.scala的HTML模板,介绍Binding.scala怎么着在完整扶助XHTML语法的还要静态检查语法错误和语义错误。

难题三:ReactJS的HTML模板成效既不齐全、也不结实

ReactJS支持用JSX编写HTML模板。

理论上,前端程序猿只要把静态HTML原型复制到JSX源文件中,
扩充一些变量替换代码,
就会更改成动态页面。
斟酌上这种做法要比Cycle.js、Widok、ScalaTags等框架更切合复用设计员提供的HTML原型。

不幸的是,ReactJS对HTML的支撑星落云散。开拓者必得手动把classfor质量替换来classNamehtmlFor,还要把内联的style体制从CSS语法改成JSON语法,代码才具运作。
这种开辟格局下,前端程序猿固然能够把HTML原型复制粘贴到代码中,但还要求多量改建技艺实际运作。
比Cycle.js、Widok、可能、ScalaTags省穿梭太多事。

除了那么些之外,ReactJS还提供了propTypes体制校验虚拟DOM的合法性。
只是,这一机制也漏洞非常多。
纵使内定了propTypes,ReactJS也不可能在编写翻译前提前开掘错误。独有测验覆盖率相当高的连串时技术在各样组件使用别的零器件时开展校验。
哪怕测验覆盖率相当的高,propTypes仍旧不可能检查评定出拼错的属性名,假如您把onClick写成了onclick
ReactJS就不会报错,往往以致开采者额外开销一大波时日排查三个很容易的bug。

本人将在《More than React(四卡塔尔国HTML也足以编写翻译?》中相比ReactJS和Binding.scala的HTML模板,介绍Binding.scala怎么着在完整支持XHTML语法的还要静态检查语法错误和语义错误。

Binding.scala 可以用 I/O 状态的绑定替代异步编制程序,从而让程序又简单又好读,对业务职员也更团结。

Binding.scala中的XHTML

近来有了Binding.scala ,能够在@dom方法中,直接编写XHTML。比方:

JavaScript

@dom def introductionDiv = { <div style="font-size:0.8em"> <h3>Binding.scala的优点</h3> <ul> <li>简单</li> <li>概念少<br/>功能多</li> </ul> </div> }

1
2
3
4
5
6
7
8
9
@dom def introductionDiv = {
  <div style="font-size:0.8em">
    <h3>Binding.scala的优点</h3>
    <ul>
      <li>简单</li>
      <li>概念少<br/>功能多</li>
    </ul>
  </div>
}

以上代码会被编译,直接成立真实的DOM对象,而从未伪造DOM。

Binding.scala对浏览器原生DOM的支撑很好,你能够在此些DOM对象上调用DOM API,与 D3、jQuery等此外库交互作用也统统没万分。

ReactJS对XHTML语法的星落云散。比较之下,Binding.scala援助完全的XHTML语法,前端技术员能够直接把规划好的HTML原型复制粘贴到代码中,整个网址就能够运行了。

标题四:ReactJS与服务器通讯时必要复杂的异步编制程序

ReactJS从服务器加载数据时的构造能够作为MVVM(Model–View–ViewModel)格局。 前端技术员必要编写制定三个数据库访谈层作为Model,把ReactJS的state当做ViewModel,而render用作View。 Model担任访谈数据库并把数据设置到state(即View Model)上,可以用Promise和fetch API实现。 然后,render,即View,担当把View Model渲染到页面上。

在那总体流程中,前端程序猿需求编写制定大批量闭包组成的异步流程, 设置、访谈状态的代码五零四散, 一超大心就能bug丛生,就算小心审慎的拍卖种种异步事件,也会促成程序变得复杂,既难调节和测量检验,又难保险。

作者就要《More than React(五卡塔尔国为啥别用异步编制程序?》中相比ReactJS和Binding.scala的数码同步模型,介绍Binding.scala怎么样自动同步服务器数据,防止手动异步编制程序。

主题素材四:ReactJS与服务器通讯时须求复杂的异步编制程序

ReactJS从服务器加载数据时的布局能够看成MVVM(Model–View–ViewModel)格局。
前端技术员需求编写制定四个数据库访谈层作为Model,把ReactJS的state当做ViewModel,而render当做View。
Model肩负访问数据库并把多少设置到state(即View Model)上,可以用Promise和fetch API实现。
然后,render,即View,担任把View Model渲染到页面上。

在这里总体流程中,前端程序猿需求编写制定多量闭包组成的异步流程,
安装、访谈状态的代码五零四散,
轻率就能够bug丛生,就算小心谨慎的管理各个异步事件,也会促成程序变得复杂,既难调节和测量检验,又难保险。

本人将要《More than React(五卡塔 尔(阿拉伯语:قطر‎为何别用异步编制程序?》中比较ReactJS和Binding.scala的数目同步模型,介绍Binding.scala怎么着自动同步服务器数据,幸免手动异步编制程序。

本身将以多个从 Github 加载头像的 DEMO 页面为例,表明为啥异步编制程序会以致代码变复杂,以至 Binding.scala 怎样减轻这些难题。

Binding.scala中XHTML的类型

@dom艺术中XHTML对象的项目是Node的派生类。

比如,<div></div> 的品类便是HTMLDivElement,而 <button></button> 的项目正是 HTMLButtonElement。

此外, @dom 注明会更正总体艺术的重临值,包装成二个Binding。

JavaScript

@dom def typedButton: Binding[HTMLButtonElement] = { <button>按钮</button> }

1
2
3
@dom def typedButton: Binding[HTMLButtonElement] = {
  <button>按钮</button>
}

注意typedButton是个原生的HTMLButtonElement,所以能够从来对它调用 DOM API。举个例子:

JavaScript

@dom val autoPrintln: Binding[Unit] = { println(typedButton.bind.innerHTML) // 在调节新竹打字与印刷开关内部的 HTML } autoPrintln.watch()

1
2
3
4
@dom val autoPrintln: Binding[Unit] = {
  println(typedButton.bind.innerHTML) // 在控制台中打印按钮内部的 HTML
}
autoPrintln.watch()

这段代码中,typedButton.bind.innerHTML 调用了 DOM API HTMLButtonElement.innerHTML。通过autoPrintln.watch(),每当开关产生更新,autoPrintln中的代码就能够施行一回。

结论

固然Binding.scala初看上去很像ReactJS, 但隐蔽在Binding.scala背后的编写制定更简约、更通用,与ReactJS和Widok楚河汉界。

因此,通过简化概念,Binding.scala灵活性更加强,能用通用的主意解决ReactJS消释不了的复杂性难点。

举例,除了上述两个地方以外,ReactJS的情景管理也是倒悬之危难点,假诺引进Redux也许react-router那样的第三方库来管理情状,会以致布局变复杂,分层变多,代码绕来绕去。而Binding.scala能够用和页面渲染一样的数码绑定机制描述复杂的情事,无需任何第三方库,就能够提供服务器通讯、状态管理和网站分发的作用。

以下表格中列出了上述Binding.scala和ReactJS的效果差别:

Binding.scala

ReactJS

复用性

细微复用单位

方法

组件

复用难度

无论是人机联作内容照旧静态内容都轻便复用

轻松复用静态内容组件,但麻烦复用交互作用组件

页面渲染算法

算法

准确的多少绑定

虚拟 DOM

性能

正确性

活动保险科学

亟需开荒者手动设置 key 属性,不然复杂的页面会混杂。

HTML 模板

语法

Scala XML 字面量

JSX

是或不是援助 HTML 或 XHTML 语法

后生可畏体化扶持 XHTML

残破支持。不奇怪的 XHTML 不可能编写翻译。开采者必得手动把 classfor 属性替换来 classNamehtmlFor,还要把内联的 style 样式从 CSS 语法改成 JSON 语法。

怎么校验模板语法

电动编写翻译时校验

运作时通过 propTypes 校验但不可能检验大致的拼写错误。

服务器通信

机制

活动远程数据绑定

MVVM 异步编程

福寿无疆难度

简单

复杂

其他

怎么样分摊网站只怕锚点链接

支撑把网站当成普通的绑定变量来用,没有必要第三方库。

不扶持,需求第三方库 react-router

功用康健性

完整的前端开辟建设方案

本身只包涵视图部分功用。必要格外领悟 react-router 、 Redux 等级三方库技能促成意气风发体化的前端项目。

学习曲线

API 轻便,对没用过 Scala 的人来讲也很好懂

上心灵。但效益太弱引致中期学习第三方库时曲线陡峭。

Binding.scala

ReactJS

多个多月前,小编在Scala.js的论坛发表Binding.scala时,这时Scala.js社区最风靡的响应式前端编制程序框架是Widok。TimNieradzik是Widok的小编。他在收看自家公布的框架后,陈赞这几个框架是Scala.js社区最有前途的 HTML 5渲染框架。

他是没有错,多个月后,今后Binding.scala已经改为Scala.js社区最风靡的响应式前端编制程序框架。

Awesome Scala网站相比较之下了Scala的响应式前端编制程序框架,Binding.scala的活跃程度和流行度都比Udash、Widok等此外框架要高。

图片 2

自己在后天的几个品类中,也逐步扬弃JavaScript和ReactJS,改用Scala.js和Binding.scala搭建新时代的前端本事栈。

结论

固然Binding.scala初看上去很像ReactJS,
但蒙蔽在Binding.scala背后的机制更简单、更通用,与ReactJS和Widok判若霄壤。

故而,通过简化概念,Binding.scala灵活性越来越强,能用通用的章程解决ReactJS解决不了的眼花缭乱难题。

譬喻,除了上述八个地点以外,ReactJS的情事管理也是为难难题,倘使引进Redux大概react-router这样的第三方库来拍卖状态,会以致构造变复杂,分层变多,代码绕来绕去。而Binding.scala能够用和页面渲染同样的多少绑定机制描述复杂的景色,不须求其余第三方库,就能够提供服务器通讯、状态管理和网站分发的效果。

以下表格中列出了上述Binding.scala和ReactJS的成效差距:

3-sheet.png

四个多月前,作者在Scala.js的论坛发表Binding.scala时,那时候Scala.js社区最盛行的响应式前端编制程序框架是Widok。TimNieradzik是Widok的小编。他在察看笔者发布的框架后,赞誉那个框架是Scala.js社区最有前程的 HTML 5渲染框架。

她是对的,八个月后,今后Binding.scala已经形成Scala.js社区最风靡的响应式前端编程框架。

Awesome Scala网站对待了Scala的响应式前端编制程序框架,Binding.scala的外向程度和流行度都比Udash、Widok等任何框架要高。

本人在近年的多少个门类中,也日渐废弃JavaScript和ReactJS,改用Scala.js和Binding.scala搭建新时期的前端手艺栈。

DEMO 效能必要

作为 DEMO 使用者,张开页面后会见到一个文本框。

在文本框中输入随机 Github 客户名,在文本框下方就能够来得客户名对应的头像。

图片 3

从 Github 加载头像

要想实现那么些须求,可以用 Github API 发送获得客户新闻的 HTTPS 请求。

出殡央浼并渲染头像的欧洲经济共同体流程的检验收下标准如下:

  • 若是客商名称为空,显示“请输入客商名”的唤醒文字;
  • 万后生可畏顾客名非空,发起 Github API,并基于 API 结果显示不一样的内容:
    • 如果没有加载完,展现“正在加载”的提醒信息;
    • 假定成功加载,把应对拆解深入分析成 JSON,从当中提取头像 UHighlanderL 并显示;
    • 大器晚成经加载时出错,突显错误音讯。

其他HTML节点

Binding.scala支持HTML注释:

JavaScript

@dom def comment = { <!-- 你看不见小编 --> }

1
2
3
@dom def comment = {
  <!-- 你看不见我 -->
}

Binding.scala也支持CDATA块:

JavaScript

@dom def inlineStyle = { <section> <style><![CDATA[ .highlight { background-color:gold } ]]></style> <p class="highlight">Binding.scala真好用!</p> </section> }

1
2
3
4
5
6
7
8
9
10
@dom def inlineStyle = {
  <section>
    <style><![CDATA[
      .highlight {
        background-color:gold
      }
    ]]></style>
    <p class="highlight">Binding.scala真好用!</p>
  </section>
}

相关链接

  • Binding.scala 项目主页
  • Binding.scala • TodoMVC 项目主页
  • Binding.scala • TodoMVC DEMO
  • Binding.scala • TodoMVC 以外的别样 DEMO
  • JavaScript 到 Scala.js 移植指南
  • Scala.js 项目主页
  • Scala API 仿照效法文书档案
  • Scala.js API 参谋文书档案
  • Scala.js DOM API 参谋文书档案
  • Binding.scala快速上手指南
  • Binding.scala API参照他事他说加以考察文书档案
  • Binding.scala 的 Gitter 聊天室

    1 赞 5 收藏 15 评论

有关链接

  • Binding.scala 项目主页
  • Binding.scala • TodoMVC 项目主页
  • Binding.scala • TodoMVC DEMO
  • Binding.scala • TodoMVC 以外的其余DEMO
  • JavaScript 到 Scala.js 移植指南
  • Scala.js 项目主页
  • Scala API 参谋文书档案
  • Scala.js API 参考文书档案
  • Scala.js DOM API 参考文书档案
  • Binding.scala快速上手指南
  • Binding.scala API参照他事他说加以考查文书档案
  • Binding.scala 的 Gitter 聊天室

异步编制程序和 MVVM

千古,大家在前端开荒中,会用异步编程来发送诉求、获取数据。举例ECMAScript 二零一六 的 Promise 和 HTML 5 的 fetch API。

而要想把那些数量渲染到网页上,大家过去的做法是用 MVVM 框架。在获取数据的经过中持续改进 View Model ,然后编写 View 把 View Model 渲染到页面上。那样一来,页面上就足以反映出加载进度的动态音信了。比如,ReactJS 的 state 就是 View Model,而 render 则是 View ,担任把 View Model 渲染到页面上。

用 ReactJS 和 Promise 的完结如下:

class Page extends React.Component {

  state = {
    githubUserName: null,
    isLoading: false,
    error: null,
    avatarUrl: null,
  };

  currentPromise = null;

  sendRequest(githubUserName) {
    const currentPromise = fetch(`https://api.github.com/users/${githubUserName}`);
    this.currentPromise = currentPromise;
    currentPromise.then(response => {
      if (this.currentPromise != currentPromise) {
        return;
      }
      if (response.status >= 200 && response.status < 300) {
        return response.json();
      } else {
        this.currentPromise = null;
        this.setState({
          isLoading: false,
          error: response.statusText
        });
      }
    }).then(json => {
      if (this.currentPromise != currentPromise) {
        return;
      }
      this.currentPromise = null;
      this.setState({
        isLoading: false,
        avatarUrl: json.avatar_url,
        error: null
      });
    }).catch(error => {
      if (this.currentPromise != currentPromise) {
        return;
      }
      this.currentPromise = null;
      this.setState({
        isLoading: false,
        error: error,
        avatarUrl: null
      });
    });
    this.setState({
      githubUserName: githubUserName,
      isLoading: true,
      error: null,
      avatarUrl: null
    });
  }

  changeHandler = event => {
    const githubUserName = event.currentTarget.value;
    if (githubUserName) {
      this.sendRequest(githubUserName);
    } else {
      this.setState({
        githubUserName: githubUserName,
        isLoading: false,
        error: null,
        avatarUrl: null
      });
    }
  };

  render() {
    return (
      <div>
        <input type="text" onChange={this.changeHandler}/>
        <hr/>
        <div>
          {
            (() => {
              if (this.state.githubUserName) {
                if (this.state.isLoading) {
                  return <div>{`Loading the avatar for ${this.state.githubUserName}`}</div>
                } else {
                  const error = this.state.error;
                  if (error) {
                    return <div>{error.toString()}</div>;
                  } else {
                    return <img src={this.state.avatarUrl}/>;
                  }
                }
              } else {
                return <div>Please input your Github user name</div>;
              }
            })()
          }
        </div>
      </div>
    );
  }

}

累积用了 100 行代码。

出于一切流程由若干个闭包构成,设置、访谈状态的代码五零四散,所以调试起来很麻烦,笔者花了四个晚上才调通这100 行代码。

内嵌Scala代码

除去能够把XHTML内嵌在Scala代码中的 @dom 方法中,Binding.scala 还扶植用 { ... } 语法把 Scala 代码内嵌到XHTML中。比方:

JavaScript

@dom def randomParagraph = { <p>生成三个自由数: { math.random.toString }</p> }

1
2
3
@dom def randomParagraph = {
  <p>生成一个随机数: { math.random.toString }</p>
}

XHTML中内嵌的Scala代码能够用 .bind 绑定变量或然调用别的 @dom 方法,比如:

JavaScript

val now = Var(new Date) window.setInterval(1000) { now := new Date } @dom def render = { <div> 现在时刻:{ now.bind.toString } { introductionDiv.bind } { inlineStyle.bind } { typedButton.bind } { comment.bind } { randomParagraph.bind } </div> }

1
2
3
4
5
6
7
8
9
10
11
12
13
val now = Var(new Date)
window.setInterval(1000) { now := new Date }
 
@dom def render = {
  <div>
    现在时间:{ now.bind.toString }
    { introductionDiv.bind }
    { inlineStyle.bind }
    { typedButton.bind }
    { comment.bind }
    { randomParagraph.bind }
  </div>
}

上述代码渲染出的网页中,时间会动态退换。

关于我:ThoughtWorks

图片 4

ThoughtWorks是一家中外IT咨询集团,追求卓越软件品质,致力于科技(science and technology)驱动商业变革。专长构建定制化软件出品,扶助顾客高效将概念转变为价值。同期为客商提供客户体验设计、技艺战略咨询、组织转型等咨询服务。 个人主页 · 小编的小说 · 84 ·   

图片 5

Binding.scala

今昔大家有了 Binding.scala ,由于 Binding.scala 扶助自动远程数据绑定,可以这么写:

@dom def render = {
  val githubUserName = Var("")
  def inputHandler = { event: Event => githubUserName := event.currentTarget.asInstanceOf[Input].value }
  <div>
    <input type="text" oninput={ inputHandler }/>
    <hr/>
    {
      val name = githubUserName.bind
      if (name == "") {
        <div>Please input your Github user name</div>
      } else {
        val githubResult = FutureBinding(Ajax.get(s"https://api.github.com/users/${name}"))
        githubResult.bind match {
          case None =>
            <div>Loading the avatar for { name }</div>
          case Some(Success(response)) =>
            val json = JSON.parse(response.responseText)
            <img src={ json.avatar_url.toString }/>
          case Some(Failure(exception)) =>
            <div>{ exception.toString }</div>
        }
      }
    }
  </div>
}

一共 25 行代码。

完整的 DEMO 请访问 ScalaFiddle。

为此这么轻巧,是因为 Binding.scala 能够用 FutureBinding 把 API 央求当成普通的绑定表明式使用,表示 API 央浼的当前情状。

每个 FutureBinding 的情事有三种可能,None代表操作正在进展,Some(Success(...))代表操作成功,Some(Failure(...))表示操作战败。

还记得绑定表达式的 .bind 吗?它表示“each time it changes”。
由于 FutureBinding 也是 Binding 的子类型,所以大家就足以接受 .bind ,表明出“每当远端数据的事态改造”的语义。

结果便是,用 Binding.scala 时,大家编辑的每风姿洒脱行代码都得以对应检验收下规范中的一句话,描述着事情规范,而非“异步流程”那样的本领细节。

让大家回想一下检验收下规范,看看和源代码是怎么风华正茂风华正茂对应的:

  • 若是顾客名称为空,彰显“请输入客商名”的唤醒文字;

    if (name == "") {
      <div>Please input your Github user name</div>
    
  • 万意气风发客商名非空,发起 Github API,并依附 API 结果显示不一样的剧情:

    } else {
      val githubResult = FutureBinding(Ajax.get(s"https://api.github.com/users/${name}"))
      githubResult.bind match {
    
    • 只要未有加载完,突显“正在加载”的提示新闻;

      case None =>
        <div>Loading the avatar for { name }</div>
      
    • 固然成功加载,把回应解析成 JSON,从当中提取头像 UOdysseyL 并展现;

      case Some(Success(response)) =>
        val json = JSON.parse(response.responseText)
        <img src={ json.avatar_url.toString }/>
      
    • 如果加载时出错,展现错误新闻。

      case Some(Failure(exception)) => // 如果加载时出错,
        <div>{ exception.toString }</div> // 显示错误信息。
      
  • } }

强类型的 XHTML

Binding.scala中的XHTML 都协理静态类型检查。比如:

JavaScript

@dom def typo = { val myDiv = <div typoProperty="xx">content</div> myDiv.typoMethod() myDiv }

1
2
3
4
5
@dom def typo = {
  val myDiv = <div typoProperty="xx">content</div>
  myDiv.typoMethod()
  myDiv
}

由于以上代码有拼写错误,编写翻译器就能够报错:

JavaScript

typo.scala:23: value typoProperty is not a member of org.scalajs.dom.html.Div val myDiv = <div typoProperty="xx">content</div> ^ typo.scala:24: value typoMethod is not a member of org.scalajs.dom.html.Div myDiv.typoMethod() ^

1
2
3
4
5
6
typo.scala:23: value typoProperty is not a member of org.scalajs.dom.html.Div
        val myDiv = <div typoProperty="xx">content</div>
                     ^
typo.scala:24: value typoMethod is not a member of org.scalajs.dom.html.Div
        myDiv.typoMethod()
              ^

结论

正文相比了 ECMAScript 二〇一六 的异步编程和 Binding.scala 的 FutureBinding 三种通讯手艺。Binding.scala 概念更加少,功用更加强,对作业愈发和睦。

表格.png

那五篇小说介绍了用 ReactJS 达成复杂交互作用的前端项指标多少个难点,以至Binding.scala 如何搞定这么些困难,包涵:

  • 复用性
  • 属性和正确性
  • HTML模板
  • 异步编程

除了那个之外上述四个方面以外,ReactJS 的景色管理也是没办法子难点,若是引进 Redux 或许 react-router 那样的第三方库来拍卖情形,会以致布局变复杂,分层变多,代码绕来绕去。而Binding.scala 能够用和页面渲染同样的数额绑定机制描述复杂的事态,无需其余第三方库,就能够提供服务器通讯、状态管理和网站分发的功效。

设若你正插足复杂的前端项目,使用ReactJS或其余耗费框架时,认为忧伤不堪,你能够用Binding.scala一举消除那些难题。Binding.scala快捷上手指南中富含了从零牵头创设Binding.scala项指标每一手续。

内联CSS属性

style 属性设置内联样式时,style 的值是个字符串。比方:

JavaScript

@dom def invalidInlineStyle = { <div style="color: blue; typoStyleName: typoStyleValue"></div> }

1
2
3
@dom def invalidInlineStyle = {
  <div style="color: blue; typoStyleName: typoStyleValue"></div>
}

以上代码中安装的 typoStyleName 样式名写错了,但编写翻译器并未报错。

要想让编写翻译器能检查内联样式,能够用 style: 前缀而不用 style 属性。比如:

JavaScript

@dom def invalidInlineStyle = { <div style:color="blue" style:typoStyleName="typoStyleValue"></div> }

1
2
3
@dom def invalidInlineStyle = {
  <div style:color="blue" style:typoStyleName="typoStyleValue"></div>
}

那么编译器就能报错:

JavaScript

typo.scala:28: value typoStyleName is not a member of org.scalajs.dom.raw.CSSStyleDeclaration <div style:color="blue" style:typoStyleName="typoStyleValue"></div> ^

1
2
3
typo.scala:28: value typoStyleName is not a member of org.scalajs.dom.raw.CSSStyleDeclaration
        <div style:color="blue" style:typoStyleName="typoStyleValue"></div>
         ^

那样一来,能够在编写制定代码时就精晓属性有未有写对。不像原生JavaScript / HTML / CSS这样,碰到bug也查不出来。

后记

Everybody's Got to Learn How to Code
——奥巴马

编制程序语言是人和微处理机对话的言语。对调节编制程序语言的人的话,Computer正是她们大脑的拉开,也是他俩肉体的大器晚成有些。所以,不会编程的人有如失去双翅的天使。

计算机程序是很奇妙的存在,它能够运作,会看、会听、会说话,好似生命同样。会编制程序的人就好像在制造生命相近,干的是上天的劳作。

本身有一个愿意,梦想编程能够像说话、写字一样的幼功手艺,被每个人都调节。

意气风发旦网页设计员精晓Binding.scala,他们不再供给找程序员落成他们的宏图,而只需求在协调的布置性稿原型上扩充法力符号.bind,就能够创设出会动的网页。

若是QA、BA或制品首席实施官掌握Binding.scala,他们写下检验收下标准后,不再供给检讨技术员干的活对不对,而得以把检验收下规范机动成为能够运行的功效。

作者拼命在Binding.scala的计划中肃清不供给的技能细节,令人使用Binding.scala时,只须求关爱他想传递给计算机的信息。

Binding.scala是自己朝着梦想迈进的小小产物。笔者梦想它不光是后面一个技术员手中的利器,也能产生平常百姓迈入编制程序神殿的踏脚石。

自定义属性

比如你需求绕开对质量的体系检查,以便为HTML元素增多定制数据,你能够属性加上 data: 前缀,比如:

JavaScript

@dom def myCustomDiv = { <div data:customAttributeName="attributeValue"></div> }

1
2
3
@dom def myCustomDiv = {
  <div data:customAttributeName="attributeValue"></div>
}

那样一来Scala编写翻译器就不会报错了。

有关链接

  • Binding.scala 项目主页
  • Binding.scala • TodoMVC 项目主页
  • Binding.scala • TodoMVC DEMO
  • Binding.scala • TodoMVC 以外的此外DEMO
  • JavaScript 到 Scala.js 移植指南
  • Scala.js 项目主页
  • Scala API 参谋文书档案
  • Scala.js API 参照他事他说加以考察文书档案
  • Scala.js DOM API 参谋文书档案
  • Binding.scala快速上手指南
  • Binding.scala API参照他事他说加以考察文书档案
  • Binding.scala 的 Gitter 聊天室

More than React类别小说:

《More than React(风华正茂卡塔尔为啥ReactJS不适合复杂的前端项目?》

《More than React(二卡塔尔国React.Component损伤了复用性?》

《More than React(三)虚拟DOM已死?》

《More than React(四卡塔尔国HTML也足以静态编写翻译?》

《More than React(五卡塔 尔(英语:State of Qatar)异步编制程序真的好啊?》

结论

正文的完好DEMO请访谈 ScalaFiddle。

从这一个示例能够见见,Binding.scala 一方面扶助完整的XHTML ,能够从高保真HTML 原型无缝移植到动态网页中,开辟进度极为通畅。其他方面,Binding.scala 能够在编写翻译时静态检查XHTML中冒出语法错误和语义错误,进而幸免bug 。

以下表格比较了ReactJS和Binding.scala对HTML语法的扶助程度:

ReactJS Binding.scala
是否支持HTML语法? 残缺支持
是否支持标准的style属性? 不支持,必须改用 JSON 语法
是否支持标准的class属性? 不支持,必须改用className
是否支持标准的for属性? 不支持,必须改用htmlFor
是否支持HTML注释? 不支持
是否兼容原生DOM操作? 不兼容
是否兼容jQuery? 不兼容
能否在编译时检查出错误? 不能

自己将要下风姿罗曼蒂克篇作品中介绍 Binding.scala 怎样兑现服务器发送央求并在页面呈现结果的流水生产线。

连带链接

  • Binding.scala 项目主页
  • Binding.scala • TodoMVC 项目主页
  • Binding.scala • TodoMVC DEMO
  • Binding.scala • TodoMVC 以外的别的DEMO
  • JavaScript 到 Scala.js 移植指南
  • Scala.js 项目主页
  • Scala API 参谋文书档案
  • Scala.js API 参照他事他说加以考察文书档案
  • Scala.js DOM API 参谋文书档案
  • Binding.scala火速上手指南
  • Binding.scala API参谋文书档案
  • Binding.scala 的 Gitter 聊天室

    1 赞 1 收藏 1 评论

有关小编:ThoughtWorks

图片 6

ThoughtWorks是一家中外IT咨询公司,追求非凡软件品质,致力于科技(science and technology)驱动商业变革。长于构建定制化软件出品,援救客商飞快将定义转变为价值。同不常间为顾客提供客户体验设计、技能计策咨询、协会转型等咨询服务。 个人主页 · 小编的文章 · 84 ·   

图片 7

本文由pc28.am发布于前端技术,转载请注明出处:异步编制程序真的好吧,不契合复杂的前端项目

上一篇:深深理解JavaScript程序中内部存款和储蓄器泄漏, 下一篇:没有了
猜你喜欢
热门排行
精彩图文
  • 前端安全
    前端安全
    Web 安全之 XSS 2018/05/25 · JavaScript· 1 评论 ·XSS 原文出处:今日头条技术博客    1.CSRF 2.XSS 基本概念 攻击原理 防御措施 什么是XSS 跨站脚本攻击(Cross Site
  • 说说Float那个被埋没的志向,重新认识Box
    说说Float那个被埋没的志向,重新认识Box
    什么是BFC 2016/01/09 · CSS · 2评论 ·BFC 原文出处:大搜车前端团队博客    这是我10个月前写的一篇关于BFC的文章,因为接下来要写一篇关于FFC的文章了,然
  • 移动端布局解决方案,一篇真正教会你开发移动
    移动端布局解决方案,一篇真正教会你开发移动
    后生可畏篇真正教会你付出活动端页面的篇章(后生可畏) 2017/12/07 · 基础手艺 ·3 评论 ·移动端 原稿出处:HcySunYang)    三个运动端的时期 蓬蓬勃勃、像素
  • 行代码完毕一个总结的区块链,写一个区块链
    行代码完毕一个总结的区块链,写一个区块链
    用 JavaScript 写二个区块链 2018/04/09 · CSS ·区块链 原稿出处: XavierDecuyper   译文出处:百度外送食物前端/JeLewine    大致种种人都据悉过像比特币和以太
  • 前面三个跨域知识总结,详细明白JS跨域难题
    前面三个跨域知识总结,详细明白JS跨域难题
    详解JS跨域问题 2016/10/31 · JavaScript· Javascript,跨域 原文出处: trigkit4(@trigkit4)    前端跨域知识总结 2016/11/04 · JavaScript· 2 评论 ·Javascript,跨域 本文作者