5、Angular中的$timeOut定时器

本文介绍AngularJS中$timeOut()函数的正确使用方法,强调在$destroy事件中取消定时器的重要性,避免引发不可预测的行为和用户体验下降。

  人们似乎常常将AngularJS中的$timeOut()函数看做是一个内置的、无须在意的函数。但是,如果你忘记了$timeOut()的回调函数将会造成非常不好的影响,你可能会因此遇到代码莫名其妙的出现问题,或者无端抛出一个错误甚至是一遍一遍的重复对的你的服务器进行$http请求这些诡异的情形。管理好你的$timeOut定时器的小技巧就是在$destory事件中将它们取消。

  和javascript中原生的setTimeout()以及setInterval()函数不同,AngularJS中的$timeOut()函数会返回一个promise。和其他的promise一样,你可以绑定$timeOut的resolved和rejected时间。然而更重要的是,你可以通过将这个promise传递给$timeOut.cancel()方法来取消掉潜在的定时器。

   在一个AngularJS应用中,这一点非常的重要,因为定时器可以结束执行那些不再与应用状态和用户界面相关的代码。最佳情形中,这些过程都会悄悄的发生;在不好的情况下,它会引起不可预测的行为并导致很差的用户体验。为了让应用顺畅的运行,你应该总是把握好你的$timeOut定时器;你需要在相应的控制器和指令接收到$destory事件时调用$timeOut.cancel()方法。

    为了更加清楚的说明这点,下面的这个例子将会有一些DOM元素通过ngSwitch/ngSwitchWhen指令来创建或销毁。注意到当$destory事件被触发时(在这里的例子中是位于指令中),我们将取消当前的定时器:

/*
 * $timeout定时器测试 
 */
// 定义控制器
test.controller(
    "DemoController",
    function( $scope ) {
        $scope.section = "htesty";
        //在toggle函数中改变section的值,以此在标记中显示/隐藏不同的部分
        $scope.toggle = function() {
            if ( $scope.section === "htesty" ) {
                $scope.section = "sad";
            } else {

                $scope.section = "htesty";

            }

        };
    }
);



//定义指令
test.directive("bnDirective", function($timeout) {

    //将用户界面的事件绑定到$scope上
    function link($scope, element, attributes) {

        //当timeout被定义时,它返回一个promise对象
        var timer = $timeout(function() {

            console.log("Timeout executed", Date.now());

        }, 3000);

        //将resolve/reject处理函数绑定到timer promise上以确保我们的cancel方法能正常运行
        timer.then(function() {

            console.log("Timer resolved!", Date.now());

        }, function() {

            console.log("Timer rejected!", Date.now());

        });

        //★当DOM元素从页面中被移除时,AngularJS将会在scope中触发$destory事件。这让我们可以有机会来cancel任何潜在的定时器
        $scope.$on("$destroy", function(event) {
            $timeout.cancel(timer);
            console.log("timer has been removed!");

        });

    }
    //返回指令的配置
    return ({
        link : link,
        scope : false
    });

});

页面中:

<div  ng-controller="DemoController">
    <h4>Don't Forget To Cancel $timeout Timers In Your $destroy Events In AngularJS</h4>

    <p>
        <a href="#" ng-click="toggle()">Toggle Section</a>
    </p>

    <div ng-switch="section">

        <p ng-switch-when="happy" bn-directive>Oh sweet!</p>

        <p ng-switch-when="sad" bn-directive >Oh noes!</p>

    </div>
</div>


结果:

"Timeout executed" 1427091576150
"Timer resolved!" 1427091576151
"timer has been removed!"


本文译自Don’t Forget To Cancel $timeout Timers In Your $destroy Events In AngularJS,

原文地址为http://www.bennadel.com/blog/2548-Don-t-Forget-To-Cancel-timeout-Timers-In-Your-destroy-Events-In-AngularJS.htm

AngularJS 中,定义自定义指令时可以注入依赖项以增强其功能。对于 `.directive('dealerMapliuzi', ...)` 的写法,如果希望注入 `$interval`、`$timeout`、`common`、`$http` 和 `$q` 等服务,必须确保这些服务是有效的,并且遵循 AngularJS 的依赖注入机制。 ### 自定义指令的依赖注入结构 AngularJS 指令的工厂函数可以通过数组注入方式声明依赖项,例如: ```javascript .directive('dealerMapliuzi', ['$interval', '$timeout', 'common', '$http', '$q', function($interval, $timeout, common, $http, $q) { // 指令逻辑 }]); ``` 这种写法是正确的,前提是所有被注入的服务都已正确定义并在应用中可用。 ### 对每个注入项的验证 1. **`$interval`** 这是一个 AngularJS 内置服务,用于执行周期性操作,类似于 `setInterval`,但与 AngularJS 的 digest 循环集成[^1]。可以在指令中安全使用。 2. **`$timeout`** 同样是 AngularJS 提供的核心服务,用于延迟执行代码,等价于 JavaScript 的 `setTimeout`,并能触发 digest 循环。适合用于异步任务。 3. **`common`** AngularJS 本身没有名为 `common` 的内置服务。如果此处指的是某个自定义服务,则必须确保该服务已在模块中注册,并通过 `angular.module().service()` 或 `factory()` 定义[^4]。 4. **`$http`** 这是 AngularJS 的核心 HTTP 客户端服务,用于发起对后端的请求。它返回一个 Promise,支持链式调用和错误处理[^5]。 5. **`$q`** `$q` 是 AngularJS 的承诺(Promise)实现,用于管理异步操作,尤其适用于需要手动控制异步流程的场景[^6]。 ### 示例:完整的指令写法 以下是一个完整的示例,展示了如何正确注入上述服务并使用它们: ```javascript angular.module('myApp') .directive('dealerMapliuzi', ['$interval', '$timeout', 'common', '$http', '$q', function($interval, $timeout, common, $http, $q) { return { restrict: 'E', link: function(scope, element, attrs) { // 使用 $timeout 延迟执行 $timeout(function() { console.log('延迟执行'); }, 1000); // 使用 $interval 定期请求数据 $interval(function() { $http.get('/api/data') .then(function(response) { // 使用 $q 处理异步结果 var deferred = $q.defer(); if (response.data) { deferred.resolve(response.data); } else { deferred.reject('无数据'); } return deferred.promise; }) .then(function(data) { common.processData(data); // 调用自定义 common 服务 }); }, 5000); } }; }]); ``` ### 总结 只要 `common` 是一个已定义的自定义服务,而其他如 `$interval`、`$timeout`、`$http` 和 `$q` 都是 AngularJS 的核心服务,那么将它们一起注入到 `.directive` 的工厂函数中是完全合法且合理的做法。这种方式允许指令访问定时器、HTTP 请求、自定义逻辑以及异步控制等功能,从而构建出更强大的组件。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值