Covention Over Configuration with JSON API
通过遵循Ember的约定,你可以显著的减少手动coding的工作量。如果在team中每个member都遵守统一的约定,那么项目代码就会易维护。
相较于拟定一系列临时的约定,Ember Data已经提供了基于JSON API的接口协议。 JSON API是一个前后端通信的数据格式标准。
(这段文字的作用就是引入了JSON API,读者可下去自行百度what is JSON API)
...
其他的文字没有特别的意义,不翻译了
Models
在Ember Data中,每一个model对象都是继承自Model类的子类实例。每一个model对象中都定义了属性,关联关系和数据的作用。
Model中可以描述从服务器返回的属性的数据类型。比如,Personmodel中定义了一个firstName属性 ---- 它是个string,还定义了一个birthday属性 ---- 它是个date:
app/models/person.js
importDSfrom'ember-data';
export defaultDS.Model.extend({
firstName:DS.attr('string'),
birthday:DS.attr('date')
});
model中同样也可以描述它与其他对象之间的关系。比如, 一个order中有很多line-items,一个line-items可以属于某个order:
(order--订单;line-items--可以理解为具体的商品)
app/models/order.js
importDSfrom'ember-data';
export defaultDS.Model.extend({
lineItems:DS.hasMany('line-item')
});
app/models/line-item.js
importDSfrom'ember-data';
export defaultDS.Model.extend({
order:DS.belongsTo('order')
});
Model(model的实例是带有实际数据的) 并没有包含实际的数据,它只是定义了属性,关联关系和实例中的数据行为等。但是!!我们可以把model对应的实例称为records-- 它是包含具体数据的对象。
Records
record是一个包含实际数据的model对象实例, 它所包含的数据来自后端服务器。当然,在 前端也可以生成一条 record,然后把该条 record 保存到服务器去。
每一条 record通过它的type和唯一的ID来区分。
比如,你现在正在编写一个通讯录应用,你或许会定义一个personmodel。每一个person实例都会有个type属性 和 一个ID属性:
this.store.findRecord('person',1); // { id: 1, name: 'steve-buscemi' }
ID通常是在该属性第一次被保存进数据库时后端赋予的。不过我们也可以在客户端来生成 ID。
Adapter
adapter可以把Ember对数据的请求(比方说:findRecord方法)翻译成我们的http请求。
比如,如果我们的应用想要获取 ID 为 1 的Personrecord,那么Ember要怎么载入这条数据? 通过HTTPorWebSocket?如果是HTTP,那么URL是/person/1or/resources/people/1?
adapter会负责来解决上述所有问题。当应用需要的数据在store中没有的时候,那么store就会询问adapter。如果你修改一条record并且保存了它,那么store就会将它递给adapter然后adapter会将对应的数据发送到服务器并且确认请求状态。
adapter使你可以完全忽略远程接口的实现方式,你只需要关注业务代码就可以了。
Caching
store会自动把record缓存下来。如果一条record之前被load过了,那么当第二次再需要它的时候,则会从store的缓存中返回该record。这样做可以减少数据在 客户端/服务器 之前的传递次数,也能让UI迅速得以渲染。
比如,你的应用将会第一次索取一个ID为1的personrecord,这时该数据将从服务器获取。
但是,下次你的应用程序再索取ID为1的person时,store会注意到它已经从服务器load并缓存了该信息。 它不会发送请求,而是从缓存中为你的应用程序返回ID为1的personrecord。 此功能 - 我们可以把它成为身份映射。
使用身份映射非常重要,因为它可以确保你在UI的某个部分所做的更改会传播到UI的其他部分。 这也意味着你不必手动保持记录同步,你需要做的就是根据ID获取你的数据,而不必担心应用的其他部分是否已经请求并加载它。
从缓存中获取数据的一个缺点就是,可能会导致缓存中的数据是陈旧的。 为了防止此陈旧数据长期存在问题,Ember Data会在每次从store返回缓存记录时都会自动发出一个请求。 当新数据被载入进入时,record会被更新,这时模版也会同步渲染。
Architecture Overview
当你的应用第一次向store索取record时,store会发现它没有本地副本并向adapter所要它。 你的adapter将从持久层中检索记录; 通常持久层指的是后端的服务器。
如上图所示,adapter若无法立即返回请求的record,就会向须向服务器发出异步请求,并且只有在该请求完成加载时才创建record。
由于这一过程是异步的,store会立即返回一个promise对象。类似的,store中所有的与adapter交互的方法都会返回 Promise。
一旦,服务器返回了请求成功的响应并返回JSON payload,adapter就会 resolvepromise,并把拿到的JSON数据交给 store。
然后store将会使用该JSON数据初始化record,并且将promiesresolve 后返回到你的应用中。
接下来,我们看一下如果store中已经有了某条record的缓存,那么获取数据的流程是什么样的:
在这种情况下,由于 store 已经知道该 record 在缓存中存在,那么它会立即把promiseresolve,并且不会询问adapter。
Model, record,adapter 和 store 是需要你理解的Ember Data的核心概念。后续的章节将会带你深入了解它们。
本节完
领取专属 10元无门槛券
私享最新 技术干货