Столкнулся с разным поведением скрипта в браузерах Mozilla Firefox v56.0 и Google Chrome v61.0.
Разница в $digest цикле. В Мозиле возникает ошибка $apply already in progress.
Пример:
var app = angular.module('app', []);
app.controller('downloadCtrl', function($scope) {
$scope.stages = [];
$scope.download = function() {
let file = new Blob(["Sample text data"]);
let fileReader = new FileReader();
fileReader.onloadstart = function() {
console.log("onloadstart");
$scope.stages.push('onloadstart');
$scope.$apply();
};
fileReader.onload = function() {
console.log("onload");
$scope.stages.push('onload');
$scope.$apply();
};
fileReader.onprogress = function(event) {
console.log("onprogress");
$scope.stages.push('onprogress');
$scope.$apply();
};
fileReader.readAsArrayBuffer(file);
};
});
app.directive('download', function($http) {
return {
restrict: 'EA',
template: `<button ng-click="download()">
Download
</button>
<div ng-repeat="stage in stages track by $index">{{stage}}</div>`,
scope: {},
controller: 'downloadCtrl',
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<download></download>
</div>
Также на jsfiddle.
Почему это происходит?
P.S. Workaround знаю, можно проверить, находимся мы уже в $digest цикле или нет, с помощью $scope.$$phase.
Интересует именно, почему так происходит.
Вроде бы событие onloadstart в Мозиле уже идет в $digest цикле. Остальные два события onload и onprogress как и ожидается выполняются вне контекста ангуляра.
Добавил печать call stack. Действительно, в Мозиле событие onloadstart происходит синхронно.
var app = angular.module('app', []);
app.controller('downloadCtrl', function($scope) {
$scope.stages = [];
function printStack(note) {
console.log((new Error("printStack: " + note)).stack.toString());
}
$scope.download = function() {
let file = new Blob(["Sample text data"]);
let fileReader = new FileReader();
printStack('sync');
fileReader.onloadstart = function() {
console.log("onloadstart");
$scope.stages.push('onloadstart');
printStack('async');
//$scope.$apply();
};
fileReader.onload = function() {
console.log("onload");
$scope.stages.push('onload');
printStack('async');
$scope.$apply();
};
fileReader.onprogress = function(event) {
console.log("onprogress", event);
$scope.stages.push('onprogress');
printStack('async');
$scope.$apply();
};
fileReader.readAsArrayBuffer(file);
};
});
app.directive('download', function($http) {
return {
restrict: 'EA',
template: `<button ng-click="download()">
Download
</button>
<div ng-repeat="stage in stages track by $index">{{stage}}</div>`,
scope: {},
controller: 'downloadCtrl',
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<download></download>
</div>
Сборка персонального компьютера от Artline: умный выбор для современных пользователей