一尘不染

为什么我会像在ng-file-upload示例用法代码中那样延迟地将函数包装在AngularJS $ timeout服务中?

angularjs

在大多数小提琴中包含ng-file-upload(https://github.com/danialfarid/ng-file-
upload)的示例用法代码,例如(http://jsfiddle.net/danialfarid/maqbzv15/1118)
/),上传响应回调函数会将其代码包装在$timeout服务调用中,但是这些调用没有传入任何延迟参数。

$timeouthttps://docs.angularjs.org/api/ng/service/
$
timeout)的Angular.js文档指示延迟是可选的,但是为什么要拨打电话,$timeout如果不延迟代码,跑。换句话说,为什么不执行以下操作:

//inject angular file upload directives and services.
var app = angular.module('fileUpload', ['ngFileUpload']);

app.controller('MyCtrl', ['$scope', 'Upload', '$timeout', function ($scope, Upload, $timeout) {
$scope.uploadPic = function(file) {
file.upload = Upload.upload({
  url: 'https://angular-file-upload-cors-srv.appspot.com/upload',
  data: {username: $scope.username, file: file},
});

file.upload.then(function (response) {
  $timeout(function () {
    file.result = response.data;
  });
}, function (response) {
  if (response.status > 0)
    $scope.errorMsg = response.status + ': ' + response.data;
}, function (evt) {
  // Math.min is to fix IE which reports 200% sometimes
  file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
});
}
}]);

$timeout在所有这些示例中,有没有理由使用包装器?以下file.upload调用可以代替它吗?:

file.upload.then(function (response) {
  file.result = response.data;
}, function (response) {
  if (response.status > 0)
    $scope.errorMsg = response.status + ': ' + response.data;
}, function (evt) {
  // Math.min is to fix IE which reports 200% sometimes
  file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
});

编辑:我可以看到它似乎没有$timeout包装程序就可以运行,但是所有示例中都包含了它,这使我认为它是有意的,这可能意味着存在安全性/健壮性/浏览器兼容性方面的问题,我在这里不了解。


阅读 252

收藏
2020-07-04

共1个答案

一尘不染

这与Angular的摘要周期有关。在继续解释摘要周期是什么之前,我将尝试通过一个示例进行演示。想象以下代码:

angular.module('app', []).controller('TestController', ['$scope', function($scope){
    $scope.name = 'Tom';
    setTimeout(function(){
        $scope.name = 'Bob';
    }, 2000);
}]);

此代码存在一个固有的问题。尽管我们$scope.name在2秒后更改了变量,但Angular完全不知道将更改为$scope.name。如果现在考虑下面的示例$timeout代替我们使用:

angular.module('app', []).controller('TestController', ['$scope', '$timeout', function($scope, $timeout){
    $scope.name = 'Tom';
    $timeout(function(){
        $scope.name = 'Bob';
    }, 2000);
}]);

Angular将在两秒钟后调用匿名函数,但是,它将从Angular的摘要周期开始。这是$timeout和之间的主要区别setTimeout,正在运行摘要循环。

摘要周期是(简单地)将Angular遍历所有观察者(绑定),检查是否有任何更改并在适当的地方重新呈现。您可能已经在$scope.$apply其他地方看到过提及-
这是开始摘要循环的方法。

关于您提供的示例:如果$timeout未使用,Angular不会知道已进行任何更改,因此,您的视图将不会更新。我$scope.$apply之前提到过,所以您可能想知道为什么我们不只是使用它呢?使用的问题$scope.$apply是您不能确定摘要循环尚未进行。如果您确实在通话时调用它,则会看到错误“
$digest is already in progress”。$timeout仅在当前周期之后运行,因此不会发生此错误。

人们经常毫不犹豫地使用$timeoutAngular通知第三方(例如您的文件上传器)已进行了更改,否则该更改将不会发生。

希望这可以清除一切。

汤姆

2020-07-04