Inferno —— 超级快速、类 React 风格的 JavaScript 用户界面库

2,614 阅读8分钟
原文链接: coyee.com
 

Inferno是一个可构建高性能用户界面的同构库,这类库针对移动设备尤其关键。Inferno和典型的虚拟DOM库不同,比如React、Mithril、Cycle和Om等,Inferno采用了智能技术来区分静态和动态的内容,这让Inferno仅仅“区分”渲染那些有动态值的内容。

除此之外,我们精心优化代码以确保它的开销尽可能的少,我们相信Inferno是当前业界最快的虚拟DOM实现框架 —— 如我们的基准测试所示,Inferno完全是为性能而生,同时还提供了一个健壮的API库,复制了诸如React等库的最佳特性。

原则上,Inferno兼容标准React API,可以毫不费劲的从React转到Inferno。此外,Inferno还有一个Babel插件,支持JSX语法,可用于优化Inferno的虚拟DOM。

关键特性

  • 最快的DOM UI渲染前端框架之一
  • 拥有类似React ES2015 API的组件inferno-component
  • 完全支持无状态组件,感谢Inferno的hooks系统提供了更多可用性
  • 同构(或通用)使得服务端渲染在Inferno-server上更简易

基准测试

安装

和React很相似,Inferno需要引入inferno包和inferno-dom包,用于浏览器DOM内的消费,还有一个用于服务端渲染的inferno-server包,用于将虚拟DOM变为HTML字符串(和React的route不一样,它是用react-dom/server做服务端渲染)。此外,组件在一个独立的inferno-component包内,具有更好的模块化,而不是像React那样通过类在核心内引入ES2015组件。

NPM:

核心包:

npm install --save inferno

ES2015有状态组件包(带生命周期事件):

npm install --save inferno-component 

浏览器DOM渲染包:

npm install --save inferno-dom 

创建Inferno的VNotes (和React.createElement相同):

npm install --save inferno-create-element

服务端渲染包:

npm install --save inferno-server 

浏览器的预加载文件:

http://infernojs.org/releases/0.7.8/inferno.min.js
http://infernojs.org/releases/0.7.8/inferno-create-element.min.js
http://infernojs.org/releases/0.7.8/inferno-component.min.js
http://infernojs.org/releases/0.7.8/inferno-dom.min.js
http://infernojs.org/releases/0.7.8/inferno-server.min.js

概述

让我们看些代码。正如你所见,Inferno在组件上有意保持了和React一致的良好设计思想:单向数据流和关注点分离。下面这些例子里,JSX通过Babel插件提供了一种展现Inferno的虚拟DOM的简单方法。

import Inferno from 'inferno';
import InfernoDOM from 'inferno-dom';

const message = "Hello world";

InfernoDOM.render(
  ,
  document.getElementById("app")
)

此外,Inferno和React一样也使用了ES6组件:

import Inferno from 'inferno';
import { Component } from `inferno-component`;
import InfernoDOM from 'inferno-dom';

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 0
    }
  }
  render() {
    return (
      

Header!

Counter is at: { this.state.counter }
) } } InfernoDOM.render(, document.body);

React和Inferno的真正区别是运行时的性能差异,Inferno能轻松处理大量复杂的DOM模型,这对于平板或手机一类的低配设备是至关重要的,用户往往要求他们的低速设备像桌面设备那样性能快速。

Inferno顶层API

Inferno.createVNode

创建一个具有链式方法的Inferno VNode对象

import createVNode from `inferno`;

InfernoDOM.render(createVNode().setTag('div').setClassName('foo').setAttrs({ id: 'test' }).setChildren('Hello world!'), document.body);

Inferno.createBlueprint

创建一个具有预定义蓝图的Inferno VNode,使用该蓝图的引用可以减少开销,提高性能。

import InfernoDOM from 'inferno-dom';

const myBlueprint = Inferno.createBlueprint({
    tag: 'div',
    attrs: {
        id: 'foo'
    },
    children: { arg: 0 }
});

InfernoDOM.render(myBl ueprint('foo'), document.body);

 

对于当作参数传给createBlueprint的对象中的每个属性,只要是用{ arg: X }形式定义的,都会被当成一个动态值(匹配调用该blueprint的参数),其他形式则被当成静态值。举个例子:如果对象是const blueprint = Inferno.createBlueprint({ tag: { arg: 0 } }),那么应该这样调用,blueprint(‘div’),即使用第一个参数作为VNode的标签。

InfernoCreateElement

创建一个Inferno VNode,这个API和React的createElement很相似

InfernoServer.renderToString

import InfernoServer from 'inferno-server';

InfernoServer.renderToString(
, document.body);

渲染一个虚节点,并添加至HTML字符串,假定已提供虚拟DOM。

钩子

请注意:钩子由inferno-dom提供;

Inferno支持DOM节点上的多种基本事件,比如onClick、onMouseOveronTouchStart,此外Inferno允许直接将普通钩子附加到组件和DOM节点上。下列表格展示了inferno-dom中的所有可用钩子:

名称触发条件回调参数onCreated一个DOM节点被创建domNodeonAttached一个DOM节点被附加在文档domNodeonWillDetach一个DOM节点将要被从文档中移除domNodeonWillUpdate一个DOM节点将要执行潜在的更新domNodeonDidUpdate一个DOM节点已经执行潜在的更新domNodeonComponentWillMount一个无状态组件即将挂载domNode, propsonComponentDidMount一个无状态组件已经挂载domNode, propsonComponentWillUnmount一个无状态组件即将被卸载domNode, propsonComponentShouldUpdate一个无状态组件已被触发更新domNode, lastProps, nextPropsonComponentWillUpdate一个无状态组件即将执行更新domNode, lastProps, nextPropsonComponentDidUpdate一个无状态组件已经更新domNode, props

 

InfernoServer.renderToString

import InfernoServer from 'inferno-server';

InfernoServer.renderToString(
, document.body);

渲染一个虚节点,并添加至HTML字符串,假定已提供虚拟DOM。

钩子

请注意:钩子由inferno-dom提供;

Inferno支持DOM节点上的多种基本事件,比如onClick、onMouseOveronTouchStart,此外Inferno允许直接将普通钩子附加到组件和DOM节点上。下列表格展示了inferno-dom中的所有可用钩子:

名称触发条件回调参数onCreated一个DOM节点被创建domNodeonAttached一个DOM节点被附加在文档domNodeonWillDetach一个DOM节点将要被从文档中移除domNodeonWillUpdate一个DOM节点将要执行潜在的更新domNodeonDidUpdate一个DOM节点已经执行潜在的更新domNodeonComponentWillMount一个无状态组件即将挂载domNode, propsonComponentDidMount一个无状态组件已经挂载domNode, propsonComponentWillUnmount一个无状态组件即将被卸载domNode, propsonComponentShouldUpdate一个无状态组件已被触发更新domNode, lastProps, nextPropsonComponentWillUpdate一个无状态组件即将执行更新domNode, lastProps, nextPropsonComponentDidUpdate一个无状态组件已经更新domNode, props

 

InfernoServer.renderToString

import InfernoServer from 'inferno-server';

InfernoServer.renderToString(
, document.body);

将一个虚拟节点渲染进 HTML 字符串,并提供虚拟的 DOM 结构。

钩子

请注意:钩子是通过 inferno-dom 提供的;

Inferno 支持很多 DOM 节点的基本事件,例如 onClick, onMouseOveronTouchStart。此外,Inferno 允许你直接在组件和 DOM 节点中附加通用事件。下表是 inferno-dom 提供的所有钩子:

名称 触发提交 回调参数
onCreated DOM 节点创建时 domNode
onAttached DOM 节点被附加到文档时 domNode
onWillDetach DOM 节点将被文档移除时 domNode
onWillUpdate DOM 节点将要执行任何潜在的更新 domNode
onDidUpdate DOM 节点已经支持完更新操作 domNode
onComponentWillMount 将要安装无状态的组件 domNode, props
onComponentDidMount 已经成功安装无状态组件 domNode, props
onComponentWillUnmount 将要卸载无状态组件 domNode, props
onComponentShouldUpdate 无状态组件被触发用于更新 domNode, lastProps, nextProps
onComponentWillUpdate 无状态组件将要更新 domNode, lastProps, nextProps
onComponentDidUpdate 无状态组件完成更新操作 domNode, props

使用钩子

为DOM节点和无状态组件隐式的分配钩子是很简单的,请注意:从inferno-component来的有状态组件(ES2015类)不支持钩子。

function createdCallback(domNode, props) {
    // [domNode] will be available for DOM nodes and components (if the component has mounted to the DOM)
    // [props] will only be passed for stateless components
}

InfernoDOM.render(
, document.body); function StatelessComponent({ props }) { return
Hello world
; } InfernoDOM.render(, document.body);

 

钩子为无状态组件提供了强大的生命周期事件支持,这样就不必被迫使用ES2015的类来构建新的组件。

性能

Inferno尝试处理创建UI组件时的两大难题:

  • 在大团队中编写大的应用程序是很慢的,尤其在开发效率和成本开销方面 —— 其实不应该
  • 通常在手机、平板或老设备上编写复杂的应用程序会导致很差的性能 —— 其实不应该
  • 编写加强的现代UI界面需要进行多次更新和加入许多动画,很容易崩溃,界面变得过于复杂 —— 其实不应该
写代码应该是件很好玩的事,随着浏览器越来越先进,技术日新月异,是时候选择一个既不对性能妥协又能提供许多乐趣的框架了。

JSX

Inferno有自己的JSX Babel plugin

和React的区别

Inferno努力保持和React基本API的兼容,只是在某些地方做了替代式的实现,当这些替换的解决方法容易采用,不用做太多改变时,一些非永久的特性就被彻底去除或是取代了。

自定义命名空间

Inferno一直想交付高性能的框架并计划如此,因此不得不对DOM状态和元素的可变性做出明智的假设,但自定义命名空间与此冲突,它可能会改变元素和属性的工作模式,所以Inferno不打算试图支持命名空间。相反,SVG的命名空间是自动应用到元素和属性上的,根据它们自身的标签名称。

有状态的ES2015组件位于独立包内

React的ES2015组件一般是作为React引用,为了减少Inferno核心的膨胀,我们提取了ES2015组件放入它自身的独立包内,具体点是inferno-component而非Inferno.Component,很多用户选择和Inferno的钩子一起使用无状态组件,它和ES2015组件具有同样的功能。

属性间的自动单位插入

Inferno不会试图在数值属性或特性上添加单位,但React会自动添加。举个例子:React处理样式

时将会造成px被自动添加。为保证
Inferno的简洁和快速,代码中并不包含这些昂贵的检查开销,也无需维护代价,完全让用户自己指定属性。因此,你可以用Inferno进行如下操作达到相同的结果

参考

测试

npm run test:browser // browser tests
npm run test:server // node tests
npm run test // browser and node tests
npm run browser // hot-loaded browser tests

编译

npm run build

检查

npm run lint:source // lint the source

Inferno由BrowserStack支持