Reputation: 20780
I have to use (large amounts of) existing code in an Angular 2 environment. That code makes extensive use of the $timeout
service from AngularJS 1.x. As opposed to various other AngularJS 1.x services that are used in the code, I am having a hard time finding a information about an Angular 2 equivalent for the $timeout
service.
The Angular docs do not seem to contain any mention of a service with timeout
-something in its name. The article Upgrading from AngularJS does mention the scenario I am facing:
Maybe you want access to AngularJS's built-in services like
$location
or$timeout
.
Unfortunately, the article does not actually explain how to access those particular services, as the subsequent example HeroesService
assumes a service without any dependencies supplied by AngularJS 1.x.
Articles such as this one suggest using the native setTimeout
function does not live up to the capabilities of the $timeout
services, either.
How can I reproduce the $timeout
functionality in the Angular 2 environment?
EDIT: As has been noted in the answers, the drawbacks of the native setTimeout
function are not relevant when using Angular 2. In that case, if I had the full $q
from AngularJS 1.x, I could replicate the $timeout
function roughly like this:
function $timeout(fn, delay) {
var result = $q.defer();
setTimeout(function () {
$q.when(fn()).then(function (v) {
result.resolve(v);
});
}, delay);
return result.promise;
}
Upvotes: 33
Views: 44287
Reputation: 105547
Use setTimeout
native function. There is no need to use special services in Angular anymore. This is due to the introduction of zones, specifically NgZone.
Articles such as this one suggest using the native setTimeout function does not live up to the capabilities of the $timeout services, either.
Why makes you say so? The main task of $timeout
service was to start digest after the delayed function is executed. You can see it from the sources:
function $TimeoutProvider() {
this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
function($rootScope, $browser, $q, $$q, $exceptionHandler) {
timeoutId = $browser.defer(function() {
try {
deferred.resolve(fn.apply(null, args));
} catch (e) {
...
if (!skipApply) $rootScope.$apply(); <-------------------- here
}, delay);
In Angular zone.js
intercepts all async operations and starts change detection in Angular which is kind of enhanced version of digest.
If you need to replicate the $timeout
, you can roughly do it like this:
function $timeout(fn, delay, ...args) {
let timeoutId;
$timeout.cancel = $timeout.cancel || function (promise) {
if (promise && promise.$$timeoutId in $timeout.promises) {
$timeout.promises[promise.$$timeoutId][1]('canceled');
delete $timeout.promises[promise.$$timeoutId];
return clearTimeout(promise.$$timeoutId);
}
return false;
};
$timeout.promises = $timeout.promises || {};
const promise = new Promise((resolve, reject) => {
timeoutId = setTimeout(function () {
try {
resolve(fn.apply(null, args));
} catch (e) {
reject(e);
} finally {
delete $timeout.promises[promise.$$timeoutId];
}
}, delay);
$timeout.promises[timeoutId] = [resolve, reject];
});
promise.$$timeoutId = timeoutId;
return promise;
}
// some basic testing
$timeout((v) => {
console.log('a', v);
}, 2000, 7);
const promise = $timeout(() => {
console.log('b');
}, 3000);
promise.catch((reason) => {
console.log(reason);
});
$timeout.cancel(promise);
Upvotes: 21