在window.alert之后的模型回调之后执行的willTransition回调中的代码

时间:2015-05-21 08:49:25

标签: firefox ember.js alert back-button html5-history

我最近遇到了Ember.js的错误。基本上当我点击Firefox中的浏览器后退按钮时,Ember.js以错误的顺序执行代码。行willTransition之后的alert("...");回调中的代码在model回调之后执行,通常应在alert("...");返回后立即执行。

代码是:

App = Ember.Application.create();
App.Router.reopen({
  location: 'history'
});
App.Router.map(function() {
  this.route('foo');
});
App.IndexRoute = Ember.Route.extend({
  actions:{
    willTransition: function(transition){
      console.log('start IndexRoute#willTransition');
      alert('See console logs');
      console.log('end IndexRoute#willTransition');
    }
  }
});
App.FooRoute = Ember.Route.extend({
  model: function() {
    console.log('start FooRoute#model');
    return [];
  }
});

有关如何重现错误的说明,请访问:https://github.com/goooooouwa/location/blob/master/README.md

在JSBin上查看此操作使用Firefox (OS X上版本12+,Windows上版本7+)中的错误:http://emberjs.jsbin.com/tefoka/

1 个答案:

答案 0 :(得分:0)

此行为的根本原因是this Firefox错误。

此错误如何导致有问题的行为

幕后发生了什么

  1. 用户点击浏览器后退按钮后,URL会发生变化,然后会更改浏览器历史记录,触发PopStateEvent,然后Ember会使用onUpdateURL()回调来处理此事件
  2. 作为回调,Ember通过调用this._doURLTransition('handleURL', url);
  3. 开始转换
  4. 在转换过程中,会创建一个Promise来确定此转换的分辨率。 Ember通过调用run.backburner.schedule('actions', function(){...})在runloop中安排承诺,因为没有创建runloop,通过调用Backburner.createAutoRun()将创建autorun
  5. function createAutorun(backburner) {
      backburner.begin();
      backburner._autorun = global.setTimeout(function() {
        backburner._autorun = null; 
        backburner.end();
      });   
    }
    

    在自动创建的runloop结束之前,执行以下代码:

    willTransition: function(transition){
      console.log('-------------- 1. start IndexRoute#willTransition -------------- ');
      alert('See console logs');
      console.log('-------------- 2. end IndexRoute#willTransition -------------- ');
    }
    

    当runloop结束时,刷新过程开始,执行以下代码:

    model: function() {
      console.log('-------------- 3. start FooRoute#model -------------- ');
      return [];
    }
    

    简化版

    以上代码与以下代码完全相同:

    console.log('processing: task #1');
    setTimeout(function(){
      console.log('processing: task #3');
    },0);
    alert('See console logs');
    console.log('processing: task #2');
    

    上面的代码错误地运行了Firefox错误,这会导致问题的Ember行为。