文档章节

Ember.js 入门指南——异步路由

ubuntuvim
 ubuntuvim
发布于 2015/10/01 02:28
字数 2246
阅读 564
收藏 4

本文将为你介绍路由的高级特性,这些高级特性可以用于处理项目复杂的异步逻辑。

           关于单词promises,直译是承诺,但是个人觉得还是使用原文吧。读起来顺畅点。

1promises承诺)

       Ember的路由处理异步逻辑的方式是使用promises。简而言之,promises就是一个表示最终结果的对象。这个对象可能是fulfill(成功获取最终结果)也可能是reject(获取结果失败)。为了获取这个最终值,或者是处理promises失败的情况都可以使用then方法,这个方法接受两个可选的回调方法,一个是promises获取结果成功时执行,一个是promises获取结果失败时执行。如果promises获取结果成功那么获取到的结果将作为成功时执行的回调方法的参数。相反的,如果promises获取结果失败,那么最终结果(失败的原因)将作为promises失败时执行的回调方法的参数。比如下面的代码段,当promises获取结果成功时执行fulfill回调,否则执行reject回调方法。

//  app/routes/promises.js
 
import Ember from 'ember';
 
export default Ember.Route.extend({
       beforeModel: function() {
              console.log('execute model()');
 
              var promise = this.fetchTheAnswer();
              promise.then(this.fulfill, this.reject);
       },
 
       //  promises获取结果成功时执行
       fulfill: function(answer) {
         console.log("The answer is " + answer);
       },
 
       //  promises获取结果失败时执行
       reject: function(reason) {
         console.log("Couldn't get the answer! Reason: " + reason);
       },
 
       fetchTheAnswer: function() {
              return new Promise(function(fulfill, reject){
                     return fulfill('success');  //如果返回的是fulfill则表示promises执行成功
                     //return reject('failure');  //如果返回的是reject则表示promises执行失败
              });
       }
});

       上述这段代码就是promises的一个简单例子,promisesthen方法会根据promises的获取到的最终结果执行不同的回调,如果promises获取结果成功则执行fulfill回调,否则执行reject回调。

       promises的强大之处不仅仅如此,promises还可以以链的形式执行多个then方法,每个then方法都会根据promises的结果执行fulfill或者reject回调。

//  app/routes/promises.js
 
import Ember from 'ember';
 
export default Ember.Route.extend({
 
       beforeModel() {
              // 注意Jquery的Ajax方法返回的也是promises
              var promiese = Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls');
              promiese.then(this.fetchPhotoOfUsers)
                            .then(this.applyInstagramFilters)
                            .then(this.uploadThrendyPhotAlbum)
                            .then(this.displaySuccessMessage, this.handleErrors);
 
       },
       fetchPhotoOfUsers: function(){
              console.log('fetchPhotoOfUsers');
       },
       applyInstagramFilters: function() {
              console.log('applyInstagramFilters');
       },
       uploadThrendyPhotAlbum: function() {
              console.log('uploadThrendyPhotAlbum');
       },
       displaySuccessMessage: function() {
              console.log('displaySuccessMessage');
       },
       handleErrors: function() {
              console.log('handleErrors');
       }
});

       这种情况下会打印什么结果呢??

       在前的文章已经使用过Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls');获取数据,是可以成功获取数据的。所以promises获取结果成功,应该执行的是获取成功对应的回调方法。浏览器控制台打印结果如下:

fetchPhotoOfUsers
applyInstagramFilters
uploadThrendyPhotAlbum
displaySuccessMessage

       但是如果我把Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls');改成一个不存在的URL,比如改成Ember.$.getJSON('https://www.my-example.com');执行代码之后控制台会提示出404错误,并且打印'handleErrors'。说明promises获取结果失败,执行了then里的reject回调。为了验证每个回调的reject方法再修改修改代码,如下:

//  app/routes/promises.js
 
import Ember from 'ember';
 
export default Ember.Route.extend({
 
       beforeModel() {
              // 注意Jquery的Ajax方法返回的也是promises
              var promiese = Ember.$.getJSON(' https://www.my-example.com ');
              promiese.then(this.fetchPhotoOfUsers, this.fetchPhotoOfUsersError)
                            .then(this.applyInstagramFilters, this.applyInstagramFiltersError)
                            .then(this.uploadThrendyPhotAlbum, this.uploadThrendyPhotAlbumError)
                            .then(this.displaySuccessMessage, this.handleErrors);
 
       },
       fetchPhotoOfUsers: function(){
              console.log('fetchPhotoOfUsers');
       },
       fetchPhotoOfUsersError: function() {
              console.log('fetchPhotoOfUsersError');
       },
       applyInstagramFilters: function() {
              console.log('applyInstagramFilters');
       },
       applyInstagramFiltersError: function() {
              console.log('applyInstagramFiltersError');
       },
       uploadThrendyPhotAlbum: function() {
              console.log('uploadThrendyPhotAlbum');
       },
       uploadThrendyPhotAlbumError: function() {
              console.log('uploadThrendyPhotAlbumError');
       },
       displaySuccessMessage: function() {
              console.log('displaySuccessMessage');
       },
       handleErrors: function() {
              console.log('handleErrors');
       }
});

       由于promises获取结果失败故执行其对应的失败处理回调。这种调用方式有点类似于try……catch……,但是本文的重点不是讲解promises,更多有关promises的教材请读者自行Google或者百度吧,在这里介绍一个jsRSVP.js,它可以你更加简单组织你的promises代码。

在附上几个promises的参考网站:

1,https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise

2,http://liubin.github.io/promises-book/

3,http://www.zhangxinxu.com/wordpress/2014/02/es6-javascript-promise-%E6%84%9F%E6%80%A7%E8%AE%A4%E7%9F%A5/

极力推荐看第二个网站的教材,个网站可以直接运行js有源PDF。非常棒!!!

 

2promises中止路由

       当发生路由切换的时候,在model回调(或者是beforeModeafterModel)中获取的数据集会在切换完成的时候传递到路由对应的controller上。如果model回调返回的是一个普通的对象(非promises对象)或者是数组,路由的切换会立即执行,但是如果model回调返回的是一个promises对象,路由的切换将会被中止直到promises执行完成(返回fulfill或者是reject)才切换。

       路由器任务任何一个包含了then方法的对象都是一个promises

       如果promises获取结果成功则会从被中止的地方继续往下执行或者是执行路由链的下一个路由,如果promises返回的依然是一个promises,那么路由依然再次被中止,等待promises的返回结果,如果是fulfill则从被中止的地方开始往下执行,以此类推,一直到获取到model回调所需的结果。

       传递到每个路由的setupController回调的值都是promises返回fulfill时的值。如下代码:

//  app/routes/tardy.js
 
import Ember from 'ember';
 
export default Ember.Route.extend({
       model: function() {
              return new Ember.RSVP.Promise(function(resolver) {
                     console.log('start......');
                     Ember.run.later(function() {
                            resolver({ msg: 'Hold your horses!!'});
                     }, 3000);
              });
       },
       setupController(controller, model) {
              console.log('msg = ' + model.msg);
       }
});

       一进入路由tardymodel回调就会被执行并且返回一个延迟3秒才执行的promises,在这期间路由会中止。当promises返回fulfill路由会继续执行,并将model返回的对象传递到setupController方法中。

       虽然这种中止的行为会影响响应速度但是这是非常必要的,特别是你需要保证model回调得到的数据是完整的数据的时候。

 

3promises获取结果失败

       文章前面主要讲的是promises获取结果成功的情况,但是如果是获取结果失败的情况又是怎么处理呢??

       默认情况下,如果model回调返回的是一个promises对象并且此promises返回的是reject,此时路由切换将被终止,也不会渲染对应的模板,并且会在浏览器控制台打印出错误日志信息,例子promises-ret-reject.js会演示。

       你可以自定义处理出错信息的逻辑,只要在routeactions哈希对象中配置即可。当promises获取结果失败的默认情况下会执行一个名为error的处理事件,否则会执行你自定义的处理事件。

//  app/routes/promises-ret-reject.js
 
import Ember from 'ember';
 
export default Ember.Route.extend({
       model: function() {
              //  为了测试效果直接返回reject
              return Ember.RSVP.reject('FAIL');
       },
       actions: {
              error: function(reason) {
                     console.log('reason = ' + reason);
 
                     //  如果你想让这个事件冒泡到顶级路由application只需要返回true
                     //  return true;
              }
       }
});

       如果没有不允许事件冒泡打印结果仅仅是“reason = FAIL”。并且页面上什么都不显示(不渲染模板)。

       如果去掉最后一行代码的注释,让事件冒泡到顶级路由application中的默认方法处理,那么结果又是什么呢?

结果是先打印了处理结果,然后再打印出提示错误的日志信息。并且页面上什么都不显示(不渲染模板)。

 

4恢复promisesreject状态

       在前面第3点介绍了promises获取结果失败时会终止路由切换,但是如果model返回是一个promises链呢?程序能到就这样死了!!!显然是不行的,做法是把model回调中返回的reject转换为fulfill。这样就可以继续执行或者切换到下一个路由了!

//  app/routes/funky.js
 
import Ember from 'ember';
 
export default Ember.Route.extend({
       model: function() {
              var promises = Ember.RSVP.reject('FAIL');
              //  由于已经知道promises返回的是reject,所以fulfill回调直接写为null
              return promises.then(null, function() {
                     return { msg: '恢复reject状态:其实就是在reject回调中继续执行fulfill状态下的代码。' };
              });
       }
});

为了验证model回调的结果,直接在模板上显示msg

<!--  app/templates/funky.hbs  -->
 
funky模板
<br>
{{model.msg}}

执行URLhttp://localhost:4200/funky,得到如下结果:

说明model回调进入到reject回调中,并正确返回了预期结果。

 

 

       到本文为止有关路由这以整章的内容也全部介绍完毕了!!难点在《Ember.js 指南——查询参数》这一篇。能力有限没有把这篇的内容讲明白,暂时搁下待日后完善!

       总的来说路由主要职责是获取数据,根据逻辑处理数据。有点MVC架构的dao层,专门做数据的CRUD操作。当然另外一个重要职责就是路由的切换,以及切换的时候参数的设置问题。

       结束完这一章下一章接着介绍组件(Component),正好是国庆休息几天再继续吧!!祝大伙国庆快乐!!!


© 著作权归作者所有

ubuntuvim
粉丝 33
博文 76
码字总数 98477
作品 1
深圳
后端工程师
私信 提问
Ember.js 入门指南——总目录

Ember.js 是什么?我想对于想学习它的人应该知道它是个什么东西,如果你想了解那就赶紧去 Google 或者百度,本系列教程是通过学习官网教程然后摘抄个人觉得比较重要的部分,加上学习实例整合...

ubuntuvim
2015/10/25
1K
2
Ember.js 入门指南--目录

本系列文章全部从(http://ibeginner.sinaapp.com/)迁移过来,欢迎访问原网站。 Ember.js 是什么?我想对于想学习它的人应该知道它是个什么东西,如果你想了解那就赶紧去 Google 或者百度,...

ubuntuvim
2015/09/07
389
2
Ember.js 入门指南——模板渲染

路由的另一个重要职责是渲染同名字的模板。 比如下面的路由设置,posts路由渲染模板posts.hbs,路由new渲染模板posts/new.hbs。 Router.map(function() { this.route('posts', function() {...

ubuntuvim
2015/09/25
449
0
Ember.js 入门指南——路由简介

从本文开始,将为大家介绍路由(route),如果你看过前面的《Ember.js 入门指南——{{link-to}} 助手》这篇文章应该初步了解了route。不过在这篇文章中只是简单介绍了路由是定义、路由层次,...

ubuntuvim
2015/09/22
476
0
Ember.js 入门指南——路由定义

当你的应用启动的时候,路由器就会匹配当前的URL到你定义的路由上。然后按照定义的路由层次逐个加载数据、设置应用程序状态、渲染路由对应的模板。 1,基本路由 在app/router.js的map方法里定...

ubuntuvim
2015/09/24
3.6K
8

没有更多内容

加载失败,请刷新页面

加载更多

Spring Boot 2 实战:使用 Spring Boot Admin 监控你的应用

1. 前言 生产上对 Web 应用 的监控是十分必要的。我们可以近乎实时来对应用的健康、性能等其他指标进行监控来及时应对一些突发情况。避免一些故障的发生。对于 Spring Boot 应用来说我们可以...

码农小胖哥
50分钟前
4
0
ZetCode 教程翻译计划正式启动 | ApacheCN

原文:ZetCode 协议:CC BY-NC-SA 4.0 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远。 ApacheCN 学习资源 贡献指南 本项目需要校对,欢迎大家提交 Pull Request。 ...

ApacheCN_飞龙
今天
4
0
CSS定位

CSS定位 relative相对定位 absolute绝对定位 fixed和sticky及zIndex relative相对定位 position特性:css position属性用于指定一个元素在文档中的定位方式。top、right、bottom、left属性则...

studywin
今天
6
0
从零基础到拿到网易Java实习offer,我做对了哪些事

作为一个非科班小白,我在读研期间基本是自学Java,从一开始几乎零基础,只有一点点数据结构和Java方面的基础,到最终获得网易游戏的Java实习offer,我大概用了半年左右的时间。本文将会讲到...

Java技术江湖
昨天
5
0
程序性能checklist

程序性能checklist

Moks角木
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部