2016-03-19 13 views
5

W większości skrzypiec zawierających przykładowy kod użycia dla przesłania pliku ng (https://github.com/danialfarid/ng-file-upload), takiego jak ten w (http://jsfiddle.net/danialfarid/maqbzv15/1118/), funkcje wywołania zwrotnego przesyłania umieszczają swój kod w rozmowie serwisowej $timeout, ale połączenia te nie mają żadnego opóźnienia parametr przekazany.

The angularjs docs dla $timeout (https://docs.angularjs.org/api/ng/service/ $ timeout) wskazują, że opóźnienie nie jest obowiązkowe, ale dlaczego chcesz, aby wykonać połączenie do $timeout jeśli nie opóźniać prowadzony kodu. Innymi słowy, zamiast z następujących, to dlaczego nie zrobić jeden po:

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

Czy jest jakiś powód, dla $timeout owijki we wszystkich tych przykładach? Czy następujące file.upload praca wezwanie na swoim miejscu ?:

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: widzę, że wydaje się działać bez $timeout owijki, ale faktem jest to zawarte we wszystkich przykładach sprawia, że ​​myślę, że to celowe, co prawdopodobnie oznacza, że ​​nie ma tu sprawy dotyczącej bezpieczeństwa/odporności/zgodności krawędzi przeglądarki.

Odpowiedz

10

Wszystko to ma związek z cyklem trawienia Angulara. Spróbuję to zademonstrować na przykładzie, zanim przejdę do wyjaśnienia, co to jest cykl trawienny. Wyobraź sobie następujący kod:

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

Występuje nieodłączny problem z tym kodem. O ile zmienimy zmienną $scope.name po 2 sekundach, Angular jest całkowicie nieświadomy tej zmiany na $scope.name. Jeśli teraz rozważmy następujący przykład, w którym używamy $timeout zamiast:

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

kątowa będzie wywołać funkcję anonimową po dwóch sekundach, jednak będzie ona następnie rozpocząć cykl trawienia kątowej za. Jest to główna różnica między $timeout i setTimeout, uruchamiany cykl trawienia.

Cykl podsumowania to (po prostu) Kątowy przejrzenie wszystkich obserwatorów (powiązań), sprawdzanie wszelkich zmian i ponowne renderowanie tam, gdzie jest to stosowne. Być może zauważyłeś wzmiankę o $scope.$apply w innym miejscu - oto jak rozpocząć cykl trawienia.

Co się tyczy podanego przykładu: Jeśli nie został użyty $timeout, Angular nie byłby świadomy, że wprowadzono jakiekolwiek zmiany i jako taki widok nie był aktualizowany. Wspomniałem wcześniej o $scope.$apply, więc możesz się zastanawiać, dlaczego nie używamy tego zamiast tego? Problem z używaniem $scope.$apply polega na tym, że nie można mieć pewności, że cykl trawienia nie jest już w toku. Jeśli zadzwonisz, gdy się zakręci, zobaczysz komunikat "$digest is already in progress". $timeout będzie działać tylko po bieżącym cyklu i jako taki, ten błąd się nie wydarzy.

Ludzie często używają $timeout bez żadnych opóźnień, aby powiadomić Angulara, że ​​zmiana została dokonana przez osobę trzecią (np. Twój program do przesyłania plików), który inaczej by się nie dowiedział.

Mam nadzieję, że to rozwiąże sprawę.

Tom

+0

Dziękuję za tę odpowiedź. Jednak, jak wyraźnie wspomniał PO, "wydaje się działać bez opakowania $ timeout". Czy możesz rzucić nieco światła na to, dlaczego wciąż działa bez opakowania $ $ timeout? – rinogo

+2

Ponadto, w zależności od potrzeb, można rozważyć użycie '$ scope. $ EvalAsync()' zamiast '$ timeout'. Źródło: https://www.bennadel.com/blog/2605-scope-evalasync-vs-timeout-in-angularjs.htm – rinogo

+2

@rinogo Mogę sobie tylko wyobrazić, że fragment kodu gdzie indziej rozpoczyna cykl trawienia. Nie jest możliwe, aby kątowe uświadomiły sobie zmiany w '$ scope', o ile nie rozpoczęto syntezy. – maddockst

1

$timeout może być użyty do asynchronicznego wywołania każdego wywołania zwrotnego. na przykład

$timeout(function callback() { 
    // code run asynchronously... 
}); 

Oznacza to, że wszystkie javascript zakończy się, zanim zostanie wywołane wywołanie zwrotne. Dodanie parametru delay do timeout opóźni wywołanie wywołania zwrotnego o wiele dalej, ale nadal będziesz uzyskiwać asynchroniczne zachowanie, niezależnie od tego, czy zapewniono opcję delay.