为什么我要像在 ng-file-upload 示例使用代码中那样在 AngularJS $timeout 服务中包装一个函数而没有延迟? [英] Why would I wrap a function in AngularJS $timeout service without a delay like they do in ng-file-upload example usage code?

查看:17
本文介绍了为什么我要像在 ng-file-upload 示例使用代码中那样在 AngularJS $timeout 服务中包装一个函数而没有延迟?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

$timeout 的 Angular.js 文档(https://docs.angularjs.org/api/ng/service/$timeout) 表示延迟是可选的,但如果不延迟,为什么要调用 $timeout正在运行的代码.换句话说,不是下面的,为什么不做后面的:

//注入角度文件上传指令和服务.var app = angular.module('fileUpload', ['ngFileUpload']);app.controller('MyCtrl', ['$scope', 'Upload', '$timeout', function ($scope, Upload, $timeout) {$scope.uploadPic = 函数(文件){file.upload = Upload.upload({url: 'https://angular-file-upload-cors-srv.appspot.com/upload',数据:{用户名:$scope.username,文件:文件},});file.upload.then(函数(响应){$超时(函数(){file.result = response.data;});}, 函数(响应){如果(响应状态> 0)$scope.errorMsg = response.status + ':' + response.data;}, 函数 (evt) {//Math.min 是为了修复有时报告 200% 的 IEfile.progress = Math.min(100, parseInt(100.0 * evt.loaded/evt.total));});}}]);

在所有这些示例中是否有任何理由使用 $timeout 包装器?下面的 file.upload 调用会代替它吗?:

file.upload.then(function (response) {file.result = response.data;}, 函数(响应){如果(响应状态> 0)$scope.errorMsg = response.status + ':' + response.data;}, 函数 (evt) {//Math.min 是为了修复有时报告 200% 的 IEfile.progress = Math.min(100, parseInt(100.0 * evt.loaded/evt.total));});

我可以看到它似乎在没有 $timeout 包装器的情况下运行,但它包含在所有示例中的事实让我认为它是故意的,这可能意味着存在安全性/稳健性/浏览器兼容性边缘情况我在这里不明白.

解决方案

这一切都与 Angular 的摘要循环有关.在我继续解释摘要循环是什么之前,我将尝试用一个例子来证明这一点.想象一下下面的代码:

angular.module('app', []).controller('TestController', ['$scope', function($scope){$scope.name = '汤姆';设置超时(功能(){$scope.name = '鲍勃';}, 2000);}]);

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

angular.module('app', []).controller('TestController', ['$scope', '$timeout', function($scope, $timeout){$scope.name = '汤姆';$超时(功能(){$scope.name = '鲍勃';}, 2000);}]);

Angular 会在两秒后调用匿名函数,但是,它会开始 Angular 的摘要循环.这是 $timeoutsetTimeout 之间的主要区别,正在运行的摘要循环.

摘要循环(简单地说)是 Angular 遍历所有观察者(绑定),检查任何更改并在适当的地方重新渲染.您可能在别处看到过对 $scope.$apply 的提及 - 这是开始摘要循环的方式.

关于您提供的示例:如果未使用 $timeout,Angular 不会意识到已进行任何更改,因此您的视图不会更新.我之前提到了 $scope.$apply 所以你可能想知道为什么我们不直接使用它?使用 $scope.$apply 的问题是您无法确定摘要循环是否已经在进行中.如果你在一个正在发生的时候调用它,你会看到一个错误$digest is already in progress".$timeout 只会在当前循环之后运行,因此不会发生此错误.

人们经常使用 $timeout 立即通知 Angular 第三方(例如您的文件上传器)进行了更改,否则它不会知道发生了变化.>

希望这能解决问题.

汤姆

In most of the fiddles containing sample usage code for ng-file-upload (https://github.com/danialfarid/ng-file-upload) like the one at (http://jsfiddle.net/danialfarid/maqbzv15/1118/), the upload response callback functions wrap their code in a $timeout service call, but these calls do not have any delay parameter passed in.

The Angular.js docs for $timeout (https://docs.angularjs.org/api/ng/service/$timeout) indicate that the delay is optional, but why would you want to make a call to $timeout if not to delay the code being run. In other words instead of the following, why not do the one after:

//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));
});
}
}]);

Is there any reason for the $timeout wrapper in all these examples? Would the following file.upload call work in its place?:

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));
});

Edit: I can see that it appears to run without the $timeout wrapper, but the fact it's included in all the examples makes me think it's deliberate, which probably means there's a security/robustness/browser compatibility edge case I don't understand here.

解决方案

It's all to do with Angular's digest cycle. I'll try to demonstrate this with an example before I go on to explain what the digest cycle is. Imagine the following code:

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

There's an inherent problem with this code. As much as we change the variable of $scope.name after 2 seconds, Angular is completely unaware of this change to $scope.name. If you now consider the following example where we use $timeout instead:

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

Angular will call the anonymous function after two seconds, however, it will then start off Angular's digest cycle. This is the main difference between $timeout and setTimeout, the digest cycle being run.

The digest cycle is (put simply) Angular going over all of the watchers (bindings), checking for any changes and re-rendering where appropiate. You may have seen a mention to $scope.$apply elsewhere - this is how to start the digest cycle.

With regards to the example you provided: If the $timeout wasn't used, Angular wouldn't be aware that any changes have been made and as such, your view wouldn't update. I mentioned $scope.$apply earlier so you may be wondering why we don't just use this instead? The problem with using $scope.$apply is that you cannot be sure that a digest cycle isn't in progress already. If you do call it while one is occcuring, you'll see an error "$digest is already in progress". $timeout will only run after the current cycle and as such, this error won't happen.

People often use $timeout without any delay to notify Angular that a change has been made by a third party (like your file uploader), that it otherwise wouldn't know had happened.

Hopefully this clears things up.

Tom

这篇关于为什么我要像在 ng-file-upload 示例使用代码中那样在 AngularJS $timeout 服务中包装一个函数而没有延迟?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆