除了在上节中描述的技术,Ember路由器通过使用errorloading substates为自定义异步跳转提供强大而可重写的约定。

一、loading Substates

1. 在跳转过程中,Ember路由器允许你从各种各样的beforeModel/model/afterModel hooks中返回promises。这些promises暂停跳转直到它们被执行,此时跳转会恢复。

2. 考虑下面的例子:

app/router.js

  1. Router.map(function() {
  2. this.route('foo', function() {
  3. this.route('slow-model');
  4. });
  5. });

app/routes/soo/slow-modal.js

  1. export default Ember.Route.extend({
  2. model() {
  3. return somePromiseThatTakesAWhileToResolve();
  4. }
  5. });
  • 如果我们访问foo/slow-model,并且在model hook中,你返回一个需要花很长时间去执行的AJAX查询promise。在这期间,你的用户界面并没有给你反馈真正正在发生什么;
  • 如果你在整个页面刷新后正在进入这个路由,你的用户界面将完全空白,你还没有完全进入任何路由,并且还没有显示任何模板;
  • 如果你从其他路由导航到foo/slow-model,你将会继续看到来自前一个路由的模板知道model完成加载,然后,很快,突然的所有foo/slow-model的模板加载了。

2. 所以,我们如何在跳转中提供一些视觉返回?

3. Ember提供了一个loading进程的默认实现,它实现了下面的loading substate行为。

app/router.js

  1. Router.map(function() {
  2. this.route('foo', function() {
  3. this.route('bar', function() {
  4. this.route('baz');
  5. });
  6. });
  7. });
  • 如果一个路径为foo.bar.baz的路由返回了一个不会被立即解析的promise,Ember将会尝试在foo.bar.baz的上层寻找一个loading route,它可以跳转进入,用foo.bar.baz的一部分作为开始:

    • foo.bar.loading
    • foo.loading
    • loading
  • Ember将会找到一个loading route在上面的位置,如果
    • 一个路由子类已经被定义为这样一个路由,例如

      • app/routes/foo/bar/loading.js
      • app/routes/foo/loading.js
      • app/routes/loading.js
    • 或者一个被正确命名的loading template已经被找到,例如
      • app/templates/foo/bar/loading.hbs
      • app/templates/foo/loading.hbs
      • app/templates/loading.hbs

4. 在一个慢的异步跳转过程中,Ember将会跳转到它找到的第一个sub-state/route,如果存在的话。中间跳转到loading substate立刻发生(同步),URL不会被更新,并且不像其他跳转,当另外一个异步跳转是活动的,当前活动的异步跳转不会被终止。

5. 在跳转到一个loading substate之后,substate对应的template,如果存在,将会被渲染到父路由主要的outlet中,例如,foo.bar.loading的模板将会渲染到foo.baroutlet中。(这对loading routes来说并不特别,这种方式是所有路由的默认行为。)

6. 一旦主要的异步跳转foo.bar.baz完成了,loading substate将会跳出,它的模板被销毁,foo.bar.baz将会被进入并且它的模板被渲染。

二、Eager VS. lazy async transitions

1. Loading substates是可选的,但是如果你提供了一个,你基本上告诉Ember你希望这个异步跳转是"eager";

2. 在没有目的的路由上loading substates,这个路由将会"lazily"留在之前跳转的路由上,直到所有目标路由的promise被解析,并且一旦跳转完成只有完全的跳转到目标路由。但是,一旦你提供一个目标路由loading substates,你就选择进入了"eager"跳转,这就是说,不像默认的"lazy",你会急切的退出源路由(并且销毁它们的模板),为了跳转到substate。URL总是立即更新除非跳转被终止或者在同一运行循环中重定向。

3. 这在错误处理上是有意义的,例如,当跳转到另一条路由失败时,一个lazy跳转将(默认的)只停留在上一个路由上,而eager跳转将已经离开了跳转前的路由并且进入了loading substate。

三、The loading event

1. 如果你从多样的beforeModel/model/afterModel hooks中返回一个promise,并且它没有立即解析,一个loading事件将会被激活到路由并且冒泡到route:application上。

2. 如果loading处理器没有被定义到指定的路由,该事件将会继续冒泡到一个跳转的支点路由,提供给route:application机会去管理它。

app/routes/foo-slow-model.js

  1. export default Ember.Route.extend({
  2. model() {
  3. return somePromiseThatTakesAWhileToResolve();
  4. },
  5. actions: {
  6. loading(transition, originRoute) {
  7. //displayLoadingSpinner();
  8. this.router.one('didTransition', function () {
  9. // hideLoadingSpinner();
  10. });
  11.  
  12. // Return true to bubble this event to `FooRoute`
  13. // or `ApplicationRoute`.
  14. return true;
  15. }
  16. }
  17. });

3. 在应用程序加载的过程中loading处理器决定做什么。如果最后的loading handler没有被定义或者返回true,Ember将会实现loading substate行为。

app/routes/application.js

  1. export default Ember.Route.extend({
  2. actions: {
  3. loading(transition, originRoute) {
  4. displayLoadingSpinner();
  5.  
  6. // substate implementation when returning `true`
  7. return true;
  8. }
  9. }
  10. });

四、error Substates

1. Ember在跳转期间遇到错误的情况下提供了一个和loading substates类似的处理。

2. 和默认的loading事件处理器怎么被实现的一样,默认的error handlers将会寻找进入合适的error substate,如果可以找到一个。

app/router.js

  1. Router.map(function() {
  2. this.route('articles', function() {
  3. this.route('overview');
  4. });
  5. });

3. 例如,从route:articles/overview#model hook被返回一个抛出的错误或者被拒绝的promise将会查找:

  • route:articles/error或者articles/error模板
  • route:error或者error模板
  • 如果上面中的一个被找到,路由器将会立刻跳转到substate(不更新URL)。错误的原因将会作为它的model被传递到error state。
  • 如果没有可视化的error substates被发现,一个错误信息将被日志记录。

五、error substates with dynamic segments

1. 带有动态字段的路由经常会被映射到一个two separate levels" 的mental model。例:

app/router.js

  1. Router.map(function() {
  2. this.route('foo', { path: '/foo/:id' }, function() {
  3. this.route('baz');
  4. });
  5. });

app/routes/foo.js

  1. export default Ember.Route.extend({
  2. model(params) {
  3. return new Ember.RSVP.Promise(function(resolve, reject) {
  4. reject("Error");
  5. });
  6. }
  7. });
  • 在URL层上你将会访问/foo/12,这将导致加载foo模板到application模板的outlet
  • 在错误事件中当尝试加载foo路由,你将也会渲染顶层的error模板到application模板的outlet
  • 这是有意的平行的行为,当foo路由从来不会被成功进入时。
  • 为了给错误创建一个foo作用域并且加载foo/errorfoooutlet,你需要拆分动态字段:
  • app/router.js
    1. Router.map(function() {
    2. this.route('foo', {path: '/foo'}, function() {
    3. this.route('elem', {path: ':id'}, function() {
    4. this.route('baz');
    5. });
    6. });
    7. });

六、The error event

1. 如果oute:articles/overviewmodel hook返回一个被拒绝的promise(例如服务器返回错误,用户没有登录等),一个error event将会被激活到route:articles/overview并且冒泡。这个error event可以被处理并且用来展示一个错误信息,重定向到登录页面。

例子:

app/routes/article-overview.js

  1. export default Ember.Route.extend({
  2. model(params) {
  3. return new Ember.RSVP.Promise(function(resolve, reject) {
  4. reject("Error");
  5. });
  6. },
  7. actions: {
  8. error(error, transition) {
  9.  
  10. if (error && error.status === 400) {
  11. // error substate and parent routes do not handle this error
  12. return this.transitionTo('modelNotFound');
  13. }
  14.  
  15. // Return true to bubble this event to any parent route.
  16. return true;
  17. }
  18. }
  19. });

2. 和loading event相似,你可以在应用程序级别管理错误事件执行任何应用程序逻辑,并基于过去的错误处理的结果,Ember将决定是否必须执行substate行为。

app/routes/application.js

  1. export default Ember.Route.extend({
  2. actions: {
  3. error(error, transition) {
  4.  
  5. // Manage your errors
  6. Ember.onerror(error);
  7.  
  8. // substate implementation when returning `true`
  9. return true;
  10.  
  11. }
  12. }
  13. });

4.11 Routing -- Loading/Error Substates的更多相关文章

  1. MySQL 8.0.11 报错[ERROR] [MY-011087] Different lower_case_table_names settings for server ('1')

    --报错信息: 2018-06-07T19:52:26.943083+08:00 0 [System] [MY-010116] [Server] /usr/local/mysql/bin/mysqld ...

  2. scala 2.11报错error: not found: type Application

    FROM: http://j-q-j.org/scala/scala-2-11-application-error.html 这两天学习scala,官网下载的最新版本2.11,书用的是<Prog ...

  3. 升级 GCC 支持C++11 或 configure: error: *** A compiler with support for C++11 language features is required.

    configure: error: *** A compiler with support for C++11 language features is required. 参考链接: (1)升级 G ...

  4. 170318 11:44:26 [ERROR] Can't start server: can't create PID file: No space left on device

    数据库挂了.打开远程,进了系统,service mysqld stop 失败.service mysqld start等了好大一会,提示Timeout error occurred trying to ...

  5. Ember.js学习教程 -- 目录

    写在前面的话: 公司的新项目需要用到Ember.js,版本为v1.13.0.由于网上关于Ember的资料非常少,所以只有硬着头皮看官网的Guides,为了加深印象和方便以后查阅就用自己拙劣的英语水平把 ...

  6. 【Maven错误】 Non-resolvable parent POM for ...... Return code is: 500 , ReasonPhrase:Internal Server Error. and 'parent.relativePath' points at no local POM @ line 14, column 11

    一.异常信息 [INFO] Scanning for projects... Downloading: http://www.myhost.com/maven/jdk18/org/springfram ...

  7. Slave I/O: Got fatal error 1236

    [起因] 一次zabbix报警,从库[Warning] MySQL-repl was down  # 不知道主库/storage空间小于20%时为什么没有触发trigger [从库错误日志] 1611 ...

  8. rabbitmq启动异常之error,{not_a_dets_file recovery.dets

    中午,公司群里面测试人员@笔者说,早上测试服务器异常,MQ起不来,重启os了也起不来,报错,上去看下了早上又因为内存oom被内核killed了,启动了下,确实启动报错,erl vm进程起来了,但是be ...

  9. 解决java.io.IOException: Cannot run program "cygpath": CreateProcess error=2, 系统找不到指定的文件 的错误

    一.外部环境: 系统环境:Windows 8 磁盘分区:只有C盘 开发环境:IntelliJ IDEA Community Edition 2016.1.3(64) 执行代码:rdd.saveAsTe ...

随机推荐

  1. 工作流JBPM_day01:5-管理流程定义3点改进

    工作流JBPM_day01:5-管理流程定义3点改进 1.打包多个文件上传 再部署一个 查询所有看看,旧版本也查出来了 2.查询时只查询所有最新的版本 3.删除指定名称指定key的所有的它的版本

  2. 分享一句话的同时说说遍历map的常用方法

    最近在网上看到一句话,鄙人觉得这是比较经典的一句话,首先要给大家分享哈: 当一个人找不到出路的时候,最好的办法就是将当前能做好的事情做到极致,做到无人能及. Map<String, String ...

  3. 查看系统资源使用情况:vmstat

    vmstat命令可以动态地查看系统资源的使用情况,如内存/交换分区/CPU的使用情况,通过使用该命令可以判断系统的瓶颈在哪里: [root@localhost ~]$ vmstat 1 5 # 表示每 ...

  4. Discuz 升级X3问题汇总整理

    最近一段时间公司的社区垃圾帖数量陡然上涨,以至于社区首页的推荐版块满满都是垃圾帖的身影,为了进一步解决垃圾帖问题我们整整花了1天时间删垃圾贴,清除不良用户,删的手都酸了,可见垃圾帖的数量之多!可耻的刷 ...

  5. Java的String详解

    Java的String详解 博客分类: Java javaStringString详解常用方法  Java的String类在开发时经常都会被使用到,由此可见String的重要性.经过这次认真仔细的学习 ...

  6. poj_2286 IDA*

    题目大意 给定一个由数字组成的#字型网格,和一定的移动规则,问最少需要多少次移动才能达到要求的结果. 题目分析 要求最少需要几步到达结果,可以考虑广度优先搜索算法,或者迭代加深深度优先搜索(IDA*) ...

  7. CSS-自定义高度的元素背景图如何自适应以及after伪元素在ie下的处理

    我都好久没更新了! 遇到一个效果,之前没有考虑清楚,设置了固定高度,到了后边,产品要加长,我就觉得设计得从新弄张长点的背景图!这不多余么? 其实分析原图还是可以再切分,再细化到不用改设计图,让我们前端 ...

  8. MyBatis官方文档——XML 映射配置文件

    XML 映射配置文件 MyBatis 的配置文件包含了影响 MyBatis 行为甚深的设置(settings)和属性(properties)信息.文档的顶层结构如下: configuration 配置 ...

  9. SSH配置优化和慢的解决方法

    author: headsen chen date: 2018-08-18  00:28:37 ssh配置优化 vim  /etc/ssh/sshd_config 1,修改root端口 2,不允许ro ...

  10. exports和module.exports区别

    参考:module.exports与exports的区别.关于exports的总结 exports 和 module.exports 的区别 module.exports是真正的模块接口,而expor ...