主干:中止以前的路由器回调执行

Backbone: abort previous router callback execution

本文关键字:路由器 回调 执行 主干      更新时间:2023-09-26

假设我的页面上有 2 个链接:

<a href="#A">Link A</a>
<a href="#B">Link B</a>

我使用骨干路由器来处理应用内页面导航。

在路由链路"#A"上,我已经为"#B"注册了一个侦听器 A 和类似的侦听器 B,其中侦听器 A 和侦听器 B 都在后台执行一些繁重的任务。

现在,假设用户单击"链接 A",并在几毫秒的间隔内单击"链接 B"。

因此,发生的情况是,当侦听器 A 完成其执行时,只有当侦听器 B 由于单个 UI 线程而开始执行时。

有没有办法,如果请求侦听器 B,我可以阻止/中止/抢占侦听器 A 的执行?

预计用户希望看到其最新操作的响应。如果两个操作相似,则不应遵循以前的操作。

要了解 Backbone 如何处理路由,让我们查看Backbone.History中的一些代码块:

 if (this._hasPushState) {
        Backbone.$(window).on('popstate', this.checkUrl);
      } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
        Backbone.$(window).on('hashchange', this.checkUrl);
      } else if (this._wantsHashChange) {
        this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
      }

如果您使用的是现代浏览器,则第二个如果黑色将订阅hashChange事件,并且任何时候您从一个链接导航到另一个链接时,它将调用checkUrl这将管理对适当操作的调用。

所以对你的问题直接回答是否定的,你不能。

但是,您可以使用一些解决方法,具体取决于您在操作中执行的操作。


第一个解决方案。

使用setTimeout()或类似的_.debounce()功能。选择所有需要保护或单独处理的链接,然后导航到所需的URL:

$(document.body).on('click', 'a:not([reference-to-out])', function(e){
   e.preventDefault();
   if (app.linkTimeoutId) {
      clearTimout(app.linkTimeoutId);
   } 
   app.linkTimeoutId = setTimeout(function () {
          app.linkTimeoutId = null;           
          app.router.navigate(e.currentTarget.pathname, {trigger: true});
   }, 500)
 });

第二个解决方案

如果您的繁重任务与网络相关(获取收集,对远程执行另一个请求),请跟踪它们保留在另一个对象中,并在 Backbone.Router 触发"路由"事件时取消它们。这将防止许多不必要的操作。

第三种解决方案

我在考虑$.Deferred对象,但在这种情况下,您应该用它包装控制器的所有操作并跟踪它们。

您可以更改 Backbone 处理路由注册的方式,以便在路由匹配和执行其回调之间引入延迟。例如

var Router = Backbone.Router.extend({
    routes: {
        ":id" : "go"
    },
    route: function(route, name, callback) {
        var router = this;
        if (!callback) callback = this[name];
        var f = function() {
            var args = _.toArray(arguments);
            console.log('Clicked route', args[0]);
            if (router.timer)
                clearTimeout(router.timer);
            router.timer = setTimeout(function() {
                callback.apply(router, args);
            }, 1000);
        };
        return Backbone.Router.prototype.route.call(router, route, name, f);
    },
    go: function(id) {
        console.log("Routed "+id);
    }
});

var r = new Router();
Backbone.history.start();

导航到路线将设置计时器。如果在给定的时间间隔内发生另一次导航,则会取消计时器并中止操作。

请参阅 http://jsfiddle.net/nikoshr/0ws8d0ky/以获取演示