【问题标题】:Angular 2 equivalent for $timeoutAngular 2 相当于 $timeout
【发布时间】:2018-01-24 15:45:35
【问题描述】:

我必须在 Angular 2 环境中使用(大量)现有代码。该代码广泛使用了 AngularJS 1.x 中的$timeout service。与代码中使用的各种其他 AngularJS 1.x 服务相反,我很难找到有关 $timeout 服务的 Angular 2 等效项的信息。

Angular docs 似乎没有提到任何名称中带有timeout-something 的服务。文章Upgrading from AngularJS 确实提到了我面临的情况:

也许您想访问 AngularJS 的内置服务,例如 $location$timeout

不幸的是,这篇文章实际上并没有解释如何访问这些特定服务,因为后续示例 HeroesService 假定服务没有 AngularJS 1.x 提供的任何依赖项。

this one 等文章建议使用原生的setTimeout function 也不符合$timeout 服务的功能。

如何在 Angular 2 环境中重现 $timeout 功能?

编辑:正如答案中所指出的那样,使用 Angular 2 时,本机 setTimeout 函数的缺点是不相关的。在这种情况下,如果我有来自 AngularJS 1.x 的完整 $q,我可以大致如下复制$timeout 函数:

function $timeout(fn, delay) {
    var result = $q.defer();
    setTimeout(function () {
        $q.when(fn()).then(function (v) {
            result.resolve(v);
        });
    }, delay);
    return result.promise;
}

【问题讨论】:

标签: javascript angular timeout


【解决方案1】:

使用setTimeout 原生函数。不再需要在 Angular 中使用特殊服务。这是由于引入了zones,特别是NgZone

诸如此类的文章建议使用本机 setTimeout 函数 也不符合 $timeout 服务的功能。

为什么让你这么说? $timeout 服务的主要任务是在延迟函数执行后启动摘要。您可以从来源中看到它:

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

在 Angular 中 zone.js 拦截所有异步操作并在 Angular 中启动更改检测 kind of enhanced version of digest

如果需要复制$timeout,大致可以这样:

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

【讨论】:

  • “为什么让你这么说?” - 好吧,链接的文章强调了一些需要 Angular 消化的超时后做事的注意事项。
  • 无论如何,我不知道如何使用setTimeout 来创建类似$timeout 的东西。我想收回一个承诺,所以在 AngularJS 1.x 中,我可能需要创建一个 deferred 并在传递给setTimeout 的函数中解决它。问题是,Angular 2 中也缺少$q.defer()
  • @O.R.Mapper,你提到的那篇文章谈到了AngularJS上下文的差异。它所说的不适用于Angular。 Angular 使用zone.js 拦截异步操作并运行摘要
  • 我已经更新了我的问题以包含一个重新创建 $timeout 功能的示例。
  • @O.R.Mapper,我已将实现添加到我的答案中。
猜你喜欢
  • 2017-02-08
  • 1970-01-01
  • 2017-07-19
  • 1970-01-01
  • 1970-01-01
  • 2019-02-08
  • 2015-11-27
  • 2019-06-20
  • 2018-08-19
相关资源
最近更新 更多