澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

异步编程真的好吗,不适合复杂的前端项目

2019-12-12 作者:澳门新萄京赌场网址   |   浏览(174)

为什么 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语法。

React.Component 损伤了复用性?

2016/09/07 · 基础技能 · binding.scala, data-binding, React, scala.js

正文笔者: 伯乐在线 - ThoughtWorks 。未经笔者许可,禁绝转发!
接待参加伯乐在线 专栏我。

本种类的上意气风发篇文章《为啥ReactJS不相符复杂的前端项目》列举了前端开辟中的各种痛点。本篇随笔上校详细索求个中“复用性”痛点。大家将用原生 DHTML API 、 ReactJS 和 Binding.scala 达成同多个索要复用的价签编辑器,然后相比多少个标签编辑器哪个完结难度更低,哪个越来越好用。

背景介绍

二〇一八年 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

此外前端框架的标题

标签编辑器的机能须求

在InfoQ的许多篇章都有标签。比方本文的竹签是“binding.scala”、“data-binding”、“scala.js”。

借使你要开辟三个博客系统,你也指望博客小编能够加上标签。所以你大概会提供标签编辑器供博客作者运用。

如图所示,标签编辑器在视觉上分为两行。

图片 2

先是行展现已经拉长的有所标签,种种标签旁边有个“x”按键能够去除标签。第二行是二个文本框和一个“Add”开关能够把文本框的剧情丰裕为新标签。每一趟点击“Add”按键时,标签编辑器应该检查标签是不是曾经增添过,避防再一次增加标签。而在功成名就增多标签后,还应清空文本框,以便客商输入新的标签。

而外客商分界面以外,标签编辑器还应当提供 API 。标签编辑器所在的页面能够用 API 填入开头标签,也足以调用 API 随即增加和删除查改标签。借使顾客增加和删除了标签,应该有某种机制通告页面包车型地铁别样部分。

主题材料意气风发: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省反复太多事。

原生 DHTML 版

先是,小编试着不用其余前端框架,直接调用原生的 DHTML API 来实现标签编辑器,代码如下:

JavaScript

<!DOCTYPE html> <html> <head> <script> var tags = []; function hasTag(tag) { for (var i = 0; i < tags.length; i ) { if (tags[i].tag == tag) { return true; } } return false; } function removeTag(tag) { for (var i = 0; i < tags.length; i ) { if (tags[i].tag == tag) { document.getElementById("tags-parent").removeChild(tags[i].element); tags.splice(i, 1); return; } } } function addTag(tag) { var element = document.createElement("q"); element.textContent = tag; var removeButton = document.createElement("button"); removeButton.textContent = "x"; removeButton.onclick = function (event) { removeTag(tag); } element.appendChild(removeButton); document.getElementById("tags-parent").appendChild(element); tags.push({ tag: tag, element: element }); } function addHandler() { var tagInput = document.getElementById("tag-input"); var tag = tagInput.value; if (tag && !hasTag(tag)) { addTag(tag); tagInput.value = ""; } } </script> </head> <body> <div id="tags-parent"></div> <div> <input id="tag-input" type="text"/> <button onclick="addHandler()">Add</button> </div> <script> addTag("initial-tag-1"); addTag("initial-tag-2"); </script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;script&gt;
    var tags = [];
 
    function hasTag(tag) {
      for (var i = 0; i &lt; tags.length; i ) {
        if (tags[i].tag == tag) {
          return true;
        }
      }
      return false;
    }
 
    function removeTag(tag) {
      for (var i = 0; i &lt; tags.length; i ) {
        if (tags[i].tag == tag) {
          document.getElementById("tags-parent").removeChild(tags[i].element);
          tags.splice(i, 1);
          return;
        }
      }
    }
 
    function addTag(tag) {
      var element = document.createElement("q");
      element.textContent = tag;
      var removeButton = document.createElement("button");
      removeButton.textContent = "x";
      removeButton.onclick = function (event) {
        removeTag(tag);
      }
      element.appendChild(removeButton);
      document.getElementById("tags-parent").appendChild(element);
      tags.push({
        tag: tag,
        element: element
      });
    }
 
    function addHandler() {
      var tagInput = document.getElementById("tag-input");
      var tag = tagInput.value;
      if (tag &amp;&amp; !hasTag(tag)) {
        addTag(tag);
        tagInput.value = "";
      }
    }
  &lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;div id="tags-parent"&gt;&lt;/div&gt;
  &lt;div&gt;
    &lt;input id="tag-input" type="text"/&gt;
    &lt;button onclick="addHandler()"&gt;Add&lt;/button&gt;
  &lt;/div&gt;
  &lt;script&gt;
    addTag("initial-tag-1");
    addTag("initial-tag-2");
  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
 

为了得以达成标签编辑器的功效,小编用了 45 行 JavaScript 代码来编排 UI 逻辑,外加若干的 HTML <div> 外加两行 JavaScript 代码填入开始化数据。

HTML 文件中硬编码了多少个 <div>。这些<div> 本人实际不是动态创设的,但能够用作容器,放置任何动态创立的成分。

代码中的函数来会把网页内容动态更新到那些 <div> 中。所以,假如要在同一个页面显示三个标签编辑器,id 就能冲突。因而,以上代码未有复用性。

就算用 jQuery 代替 DHTML API,代码复用照旧很难。为了复用 UI ,jQuery 开拓者经常必需附加增添代码,在 onload 时扫描整个网页,寻觅具备一定 class 属性的要素,然后对这一个成分进行改换。对于复杂的网页,那么些 onload 时运转的函数十分轻易就能够冲突,比方贰个函数修正了多少个 HTML 成分,平日导致另豆蔻梢头处代码受影响而其间情状错乱。

难点二: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 完成的标签编辑器组件

ReactJS 提供了足以复用的机件,即 React.Component 。假如用 ReactJS 完成标签编辑器,大约能够如此写:

JavaScript

class TagPicker extends React.Component { static defaultProps = { changeHandler: tags => {} } static propTypes = { tags: React.PropTypes.arrayOf(React.PropTypes.string).isRequired, changeHandler: React.PropTypes.func } state = { tags: this.props.tags } addHandler = event => { const tag = this.refs.input.value; if (tag && this.state.tags.indexOf(tag) == -1) { this.refs.input.value = ""; const newTags = this.state.tags.concat(tag); this.setState({ tags: newTags }); this.props.changeHandler(newTags); } } render() { return ( <section> <div>{ this.state.tags.map(tag => <q key={ tag }> { tag } <button onClick={ event => { const newTags = this.state.tags.filter(t => t != tag); this.setState({ tags: newTags }); this.props.changeHandler(newTags); }}>x</button> </q> ) }</div> <div> <input type="text" ref="input"/> <button onClick={ this.addHandler }>Add</button> </div> </section> ); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class TagPicker extends React.Component {
 
  static defaultProps = {
    changeHandler: tags =&gt; {}
  }
 
  static propTypes = {
    tags: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
    changeHandler: React.PropTypes.func
  }
 
  state = {
    tags: this.props.tags
  }
 
  addHandler = event =&gt; {
    const tag = this.refs.input.value;
    if (tag &amp;&amp; this.state.tags.indexOf(tag) == -1) {
      this.refs.input.value = "";
      const newTags = this.state.tags.concat(tag);
      this.setState({
        tags: newTags
      });
      this.props.changeHandler(newTags);
    }
  }
 
  render() {
    return (
      &lt;section&gt;
        &lt;div&gt;{
          this.state.tags.map(tag =&gt;
            &lt;q key={ tag }&gt;
              { tag }
              &lt;button onClick={ event =&gt; {
                const newTags = this.state.tags.filter(t =&gt; t != tag);
                this.setState({ tags: newTags });
                this.props.changeHandler(newTags);
              }}&gt;x&lt;/button&gt;
            &lt;/q&gt;
          )
        }&lt;/div&gt;
        &lt;div&gt;
          &lt;input type="text" ref="input"/&gt;
          &lt;button onClick={ this.addHandler }&gt;Add&lt;/button&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    );
  }
 
}
 

如上 51 行 ECMAScript 二零一四代码实现了三个标签编辑器组件,即TagPicker。纵然代码量比 DHTML 版长了一小点,但复用性大大进级了。

假令你绝不 ECMAScript 2016 的话,那么代码还组织带头人一些,並且亟需管理局部JavaScript 的坑,例如在回调函数中用持续 this

ReactJS 开拓者能够随即用 ReactDOM.render 函数把 TagPicker 渲染到别的空白成分内。其余,ReactJS 框架能够在 stateprops 改造时触发 render ,进而防止了手动改革现有的 DOM。

假如不思考冗余的 key 属性,单个组件内的相互 ReactJS 还算壮志未酬。可是,复杂的网页布局往往需求多少个构件层层嵌套,这种父亲和儿子组件之间的并行,ReactJS 就很费事了。

诸如,倘使须要在 TagPicker 之外显示全部的标签,每当顾客增加和删除标签,那几个标签也要自动更新。要贯彻那么些功能,供给给 TagPicker 传入 changeHandler 回调函数,代码如下:

JavaScript

class Page extends React.Component { state = { tags: [ "initial-tag-1", "initial-tag-2" ] }; changeHandler = tags => { this.setState({ tags }卡塔尔国; }; render(卡塔尔(英语:State of Qatar) { return ( <div> <TagPicker tags={ this.state.tags } changeHandler={ this.changeHandler }/> <h3>全部标签:</h3> <ol>{ this.state.tags.map(tag => <li>{ tag }</li> 卡塔尔(قطر‎ }</ol> </div> 卡塔尔国; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Page extends React.Component {
 
  state = {
    tags: [ "initial-tag-1", "initial-tag-2" ]
  };
 
  changeHandler = tags =&gt; {
    this.setState({ tags });
  };
 
  render() {
    return (
      &lt;div&gt;
        &lt;TagPicker tags={ this.state.tags } changeHandler={ this.changeHandler }/&gt;
        &lt;h3&gt;全部标签:&lt;/h3&gt;
        &lt;ol&gt;{ this.state.tags.map(tag =&gt; &lt;li&gt;{ tag }&lt;/li&gt; ) }&lt;/ol&gt;
      &lt;/div&gt;
    );
  }
 
}
 

为了能接触页面别的一些更新,我被迫增添了三个 21 行代码的 Page 组件。

Page 组件必得得以达成 changeHandler 回调函数。每当回调函数触发,调用 Page 自己的 setState 来触发 Page 重绘。

从那些事例,我们得以看看, ReactJS 能够归纳的搞定轻松的标题,但碰撞档案的次序复杂、人机联作频仍的网页,完成起来就很麻烦。使用 ReactJS 的前端项目充满了各样 xxxHandler 用来在组件中传递消息。作者参预的某国外顾客项目,平均每一个组件差不离供给传入三个回调函数。假设档案的次序嵌套深,创设网页时,平常要求把回调函数从最顶层的零件一头角峥嵘传入最尾巴部分的零器件,而当事件触发时,又须要后生可畏稀世把事件新闻往外传。整个前端项目有逾越四分之二代码都在此样绕圈子。

难题三: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语法的还要静态检查语法错误和语义错误。

难题三: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原型复制粘贴到代码中,整个网址就足以运作了。

Binding.scala 的主导用法

在传授 Binding.scala 怎么样促成标签编辑器早前,小编先介绍一些 Binding.scala 的根底知识:

Binding.scala 中的最小复用单位是数额绑定表明式,即 @dom 方法。每个 @dom 方法是后生可畏段 HTML 模板。例如:

JavaScript

// 两个 HTML 换行符 @dom def twoBr = <br/><br/>

1
2
3
// 两个 HTML 换行符
@dom def twoBr = &lt;br/&gt;&lt;br/&gt;
 

JavaScript

// 一个 HTML 标题 @dom def myHeading(content: String) = <h1>{content}</h1>

1
2
3
// 一个 HTML 标题
@dom def myHeading(content: String) = &lt;h1&gt;{content}&lt;/h1&gt;
 

每一个模板还足以动用bind语法包含其余子模板,比如:

JavaScript

@dom def render = { <div> { myHeading("Binding.scala的特点").bind } <p> 代码短 { twoBr.bind } 概念少 { twoBr.bind } 功能多 </p> </div> }

1
2
3
4
5
6
7
8
9
10
11
12
13
@dom def render = {
  &lt;div&gt;
    { myHeading("Binding.scala的特点").bind }
    &lt;p&gt;
      代码短
      { twoBr.bind }
      概念少
      { twoBr.bind }
      功能多
    &lt;/p&gt;
  &lt;/div&gt;
}
 

您能够仰慕附录:Binding.scala快速上手指南,学习上手Binding.scala开采的具体步骤。

其它,本种类第四篇小说《HTML也足以编写翻译》还将列出Binding.scala所支撑的欧洲经济共同体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实现的标签编辑器模板

终极,下文将展现什么用Binding.scala实现标签编辑器。

标签编辑器要比刚刚介绍的HTML模板复杂,因为它不光是静态模板,还带有交互作用。

JavaScript

@dom def tagPicker(tags: Vars[String]) = { val input: Input = <input type="text"/> val addHandler = { event: Event => if (input.value != "" && !tags.get.contains(input.value)) { tags.get = input.value input.value = "" } } <section> <div>{ for (tag <- tags) yield <q> { tag } <button onclick={ event: Event => tags.get -= tag }>x</button> </q> }</div> <div>{ input } <button onclick={ addHandler }>Add</button></div> </section> }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@dom def tagPicker(tags: Vars[String]) = {
  val input: Input = &lt;input type="text"/&gt;
  val addHandler = { event: Event =&gt;
    if (input.value != "" &amp;&amp; !tags.get.contains(input.value)) {
      tags.get = input.value
      input.value = ""
    }
  }
  &lt;section&gt;
    &lt;div&gt;{
      for (tag &lt;- tags) yield &lt;q&gt;
        { tag }
        &lt;button onclick={ event: Event =&gt; tags.get -= tag }&gt;x&lt;/button&gt;
      &lt;/q&gt;
    }&lt;/div&gt;
    &lt;div&gt;{ input } &lt;button onclick={ addHandler }&gt;Add&lt;/button&gt;&lt;/div&gt;
  &lt;/section&gt;
}
 

以此标签编辑器的 HTML 模板豆蔻年华共用了 18 行代码就达成好了。

标签编辑器中须求体现当前全体标签,所以这里用tags: Vars[String]保留全体的竹签数据,再用for/yield循环把tags中的种种标签渲染成UI成分。

Vars 是帮衬数据绑定的列表容器,每当容器中的数据发生改变,UI就能够自动改造。所以,在x按键中的onclick事件中删去tags中的数据时,页面上的价签就能够自行随之覆灭。相符,在Add按钮的onclick中向tags中加多数据时,页面上也会自动发出相应的价签。

Binding.scala不但达成标签编辑器比 ReactJS 简单,何况用起来也比 ReactJS 轻易:

JavaScript

@dom def render(卡塔尔国 = { val tags = Vars("initial-tag-1", "initial-tag-2"卡塔尔(قطر‎<div> { tagPicker(tags卡塔尔(英语:State of Qatar).bind } <h3>全体标签:</h3> <ol>{ for (tag <- tags卡塔尔 yield <li>{ tag }</li> }</ol> </div> }

1
2
3
4
5
6
7
8
9
@dom def render() = {
  val tags = Vars("initial-tag-1", "initial-tag-2")
  &lt;div&gt;
    { tagPicker(tags).bind }
    &lt;h3&gt;全部标签:&lt;/h3&gt;
    &lt;ol&gt;{ for (tag &lt;- tags) yield &lt;li&gt;{ tag }&lt;/li&gt; }&lt;/ol&gt;
  &lt;/div&gt;
}
 

假设用 9 行代码另写贰个 HTML 模板,在模板中调用刚才达成好的 tagPicker 就行了。

完整的 DEMO 请访问 。

在 Binding.scala 没有供给像 ReactJS 那样编写 changeHandler 之类的回调函数。每当客户在 tagPicker 输入新的竹签时,tags 就能够改造,网页也就能够活动随之改动。

对待 ReactJS 和 Binding.scala 的代码,能够发现以下分别:

  • Binding.scala 的开拓者能够用雷同 tagPicker 这样的 @dom 方法表示 HTML 模板,而不要求组件概念。
  • Binding.scala 的开辟者能够在措施之间传递 tags 那样的参数,而无需 props 概念。
  • Binding.scala 的开垦者能够在措施钦定义局部变量表示景况,而不供给 state 概念。

总的看 Binding.scala 要比 ReactJS 精练不菲。

只要您用过 ASP 、 PHP 、 JSP 之类的服务端网页模板语言, 你会发掘和 Binding.scala 的 HTML 模板很像。

接纳 Binding.scala 一点也无需函数式编制程序知识,只要把规划工具中变化的 HTML 原型复制到代码中,然后把会变的某个用花括号代替、把重复的有的用 for / yield 代替,网页就办好了。

结论

即使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等别的框架要高。

图片 3

自个儿在近年的多少个品种中,也逐年遗弃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。提姆Nieradzik是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 顾客名,在文本框下方就能够显得客户名对应的头像。

图片 4

从 Github 加载头像

要想完毕那一个须要,能够用 Github API 发送赢得客户音信的 HTTPS 请求。

发送诉求并渲染头像的完全流程的检验收下规范如下:

  • 倘若客商名称叫空,展现“请输入顾客名”的唤起文字;
  • 即使客商名非空,发起 Github API,并依靠 API 结果展现不一致的从头到尾的经过:
    • 生机勃勃经未有加载完,显示“正在加载”的提醒消息;
    • 设若成功加载,把应对深入分析成 JSON,从中提取头像 UTiggoL 并展现;
    • 假使加载时出错,展现错误音讯。

其他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>
}

结论

正文相比了分裂技能栈中达成和应用可复用的竹签编辑器的难度。

原生 HTML ReactJS Binding.scala
实现标签编辑器需要代码行数 45行 51行 17行
实现标签编辑器的难点 在代码中动态更新HTML页面太繁琐 实现组件的语法很笨重
使用标签编辑器并显示标签列表需要代码行数 难以复用 21行 8行
阻碍复用的难点 静态HTML元素难以模块化 交互组件之间层层传递回调函数过于复杂

Binding.scala 不表明“组件”之类的玩笑,而以更轻易的“方法”为最小复用单位,让编制程序体验特别顺风,得到了越来越好的代码复用性。

本连串下黄金年代篇作品将相比 ReactJS 的虚构 DOM 机制和 Binding.scala 的准确数据绑定机制,爆料 ReactJS 和 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 赞 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>
}

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

连带链接

  • 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 收藏 评论

关于笔者:ThoughtWorks

图片 5

ThoughtWorks是一家中外IT咨询集团,追求卓绝软件品质,致力于科学技术驱动商业变革。长于营造定制化软件出品,扶植顾客高效将定义转变为价值。同不平时间为顾客提供顾客体验设计、本领战略咨询、组织转型等咨询服务。 个人主页 · 笔者的稿子 · 84 ·   

图片 6

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,从当中提取头像 U马自达MX-5L 并体现;

      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()
              ^

有关小编:ThoughtWorks

图片 7

ThoughtWorks是一家中外IT咨询公司,追求卓绝软件品质,致力于科学技术驱动商业变革。长于营造定制化软件出品,补助顾客快速将概念转化为价值。同有时候为顾客提供客户体验设计、技能计谋咨询、组织转型等咨询服务。 个人主页 · 小编的随笔 · 84 ·   

图片 8

结论

正文相比较了 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(五)异步编制程序真的好啊?》

结论

正文的完全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

图片 9

ThoughtWorks是一家中外IT咨询公司,追求优异软件品质,致力于科学技术驱动商业变革。长于创设定制化软件出品,扶助客商快速将定义转变为价值。同期为顾客提供客商体验设计、技巧战术咨询、协会转型等咨询服务。 个人主页 · 笔者的篇章 · 84 ·   

图片 10

本文由澳门新萄京官方网站发布于澳门新萄京赌场网址,转载请注明出处:异步编程真的好吗,不适合复杂的前端项目

关键词: