本文目的是介绍falcor的基本概念和工作原理,并演示如何在egg应用中引入falcor,使得读者能快速掌握falcor的基本用法。
falcor是什么
falcor是介于客户端和服务端的数据中间件. 它把整个应用的域模型通过一个虚拟JSON对象表示,并抽象出get, set和call三种操作,使得应用程序可以用一种一致的方式读写域模型的数据,同时不用关注数据的来源。此外,falcor还提供了缓存、批量打包和去重的功能,从而减少了网络请求和往返的次数以及冗余数据的存储和传输.
三大特征
单一域模型(One model everywhere)
falcor把整个应用的域模型通过一个虚拟的Json Graph来表示(你可以暂且把这个Json Graph理解成一个大JSON对象). 这么做的好处是 业务方无需关心数据的来源, 即数据可能存储在客户端内存,数据库或某个网络节点,可以更专注业务逻辑的实现.
数据即API(The data is the api)
falcor在JSON Graph之上抽象了三种操作:get, set和call,分别对应着读取,写入和调用。由于所有对域模型的CRUD最终都通过这3种操作来表达,因此只要域模型的数据结构(即Json Graph)的结构被确定下来,那么就可以随心所欲的对域模型进行CRUD,无需额外定义一套API。
云端绑定(Bind to the cloud)
直接翻译过来不好理解。
实际上想表达的意思是,由于引入了Json Graph的概念,使得同一个实体(entity)可以通过唯一的路径来指定,并通过引用(Reference)间接表示. Falcor会自动遍历Json Graph中的引用并在需要的时候发出请求, 然后将其引用替换为真实的实体对象。同时,falcor会透明地处理所有的网络通信,并实现批处理和去重。
基本概念
为了能更好的理解和使用falcor, 需要了解一些基本概念
Json Graph
Json Graph是以Json对象来表达图信息(Graph Infomation)的一种规约。falcor使用Json Graph来表示域模型. 这么说有点抽象,看一个Json Graph例子。
{
todosById: {
"44": {
name: "get milk from corner store",
done: false,
author: {
$type: 'atom’,
value: { firstName: 'Liu', lastName: 'Archer' }
},
prerequisites: [{ $type: "ref", value: ["todosById", 54] }]
},
"54": {
name: "withdraw money from ATM",
done: false,
prerequisites: []
}
},
todos: [
{ $type: "ref", value: ["todosById", 44] },
{ $type: "ref", value: ["todosById", 54] }
]
}
JSON Graph本质上也是JSON对象,因此可以使用任何json解析器进行解析。 只不过,falcor为JSON
Graph引入了3种新的原生类型:引用(ref), 原子(atom)和错误(error). 并提供了一组工具用于转换、存储和获取这些数据, 在上面的例子,todos数组包含两个元素,这两个元素都通过引用来表达,其中todoById[44].author
被定义atom类型,因此它将会被falcor当做一个整体看待。
Paths
一组键(key)的有序序列,用于定位Json Graph中某个属性。比如有如下的Json Graph
{
todos: [
{
name: 'get milk from corner store',
done: false
}
]
}
要获取todos
数组的第一个元素中的name
属性,则需要提供这样的Path: todos[0].name
,或者用数组的形式表示: [‘todos', 0, 'name’]
Path总是从json Graph的根开始解析的
PathSets
PathSets就是若干Path的集合。Falcor允许同时从json graph中获取多个属性
DataSource
数据源是实现了JSON Graph三种抽象操作的接口。每个数据源有且仅关联一个JSON Graph
Model
Model可以理解为JSON Graph的高级接口。实际上,Model在Data Source之上,提供了缓存和格式转换等一系列的功能。这张图比较清晰的表达了 Model 和 DataSource的关系
Router
Model是工作在客户端的,如果Model需要从服务端获取数据,必须经过Router进行代理。
falcor的工作原理
falcor由客户端和服务端两部分构成。前端应用通过提供一组Paths(或PathSets), 调用Model的相关操作(get , set或call)完成数据的读写或其他处理。Model会自行解析Path,并将操作派发给DataSource执行,而部分操作可能需要交由服务端的Router ,最后Model汇总所有结果并返回。期间,model会做一些优化,比如缓存优化,请求合并等.
如何引入falcor
服务端
falcor 为express 和 koa应用提供了路由适配,见[falcor-kao-router]和[falcor]。 下面说一下如何在egg应用中引入falcor。
首先安装falcor-route
、falcor-koa-router
、falcor-json-graph
npm i -S falcor-router falcor-koa falcor-json-graph
falcor-json-graph
不是必须的,它是一个用于生成json graph片段的辅助库。但一般会使用它减少编码复杂度
接着定义falcor路由。为了和egg controller区别开来,建议把falcor路由文件放到app/falcor
目录下
// app/falcor/index.js
const router = require('falcor-koa-router');
module.exports = router.routes([
{
route: 'greeting',
* get() {
// this 指向 egg application
const ctx = this.ctx;
return dataMock.greeting(ctx);
}
},
// more falcor routes
]);
最后在app/router.js
加入falcor路由
// app/router.js
const falcorRouter = require('./falcor/index');
module.exports = app => {
router.all('/model.json', falcorRouter);
// more egg routes
};
客户端
- UMD方式。
在页面上通过<script>
标签引入falcor.browser.js
<script src="https://netflix.github.io/falcor/build/falcor.browser.js"></script>
然后通过window.falcor
引用
var model = new window.falcor.Model({
source: new falcor.HttpDataSource('/model.json', {
timeout: 60000,
})
});
model.getValue(‘/greeting’).then(e => console.log(e));
- CMD方式,,
安装falcor依赖
npm i -D falcor
通过require
或import
方式导入falcor
var falcor = require('falcor');
最后通过构建工具(如webpack等)打包到jsbundle
完整的egg-falcor例子见 这里
其他资源
常用的库
- falcor-router 用于构造falcor路由的基础库
- falcor-koa-router 适配 koa 中间件的falcor路由
- falcor-express 适配express中间件的falcor路由
- falcor-json-graph 用于生成各种常见的Json Graph