Angular的承诺是异步的吗?

时间:2016-02-27 16:10:47

标签: javascript angularjs asynchronous angular-promise

我可能会错过一些关于Angular的承诺,但我想知道一些事情:承诺是异步的吗?我不确定是否异步'是正确的词,但让我解释一下自己。

在我的代码中,我使用promises做了一个非常大的过程(读取和写入数百个大文件),同时我显示一个加载栏来观察过程的进度。我注意到即使我的代码在一个承诺中,它似乎也不是异步并冻结显示(我假设是由主线程管理)。

例如,在您可以在此Plnkr中找到的代码中,我想知道如何在大进程完成时让进度条移动。我理解为什么当我在主线程中调用它时它会冻结,而不是在我使用Angular的承诺时。



var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope, $q) {
  
  function hugeProcess () {
    var i = 0;
    var start = new Date().getTime();
    while (i++ < 100000) {
      console.log(i);
    }
    var end = new Date().getTime();
      var time = end - start;
      $scope.processTime = 'Done in ' + time  + 'ms';
  }
  
  $scope.onClickStartHugeProcess = function () {
    console.log('onClickStartHugeProcess');
    hugeProcess();
  };
  
  $scope.onClickStartHugeProcessWithPromise = function () {
    console.log('onClickStartHugeProcessWithPromise');
    $q.when()
    .then(function () {
      return hugeProcess();
    });
  };
});
&#13;
&#13;
&#13;

3 个答案:

答案 0 :(得分:1)

代码中的问题是您的hugeProcess函数永远不会产生。所以是的,它是异步调用的(then回调总是在Promises / A + promise实现中异步调用),但这不会改变调用它时hugeProcess正在做什么,这会占用主要内容UI线程,使其在运行时不会发生任何其他事情。只有一个主要的UI线程,所有的JavaScript都运行在除web workers之外的那个主UI线程上。

要让hugeProcess不这样做,你必须通过setTimeout(或者可能内置于Angular中的内容)将其分解并让它在短暂延迟后自行调用。

作为Joe Clay points out,这段代码没有多大意义:

$q.when()
.then(function () {
  return hugeProcess();
});

这是有效的:

setTimeout(hugeProcess, 0);

...因为没有参数的$q.when()返回已解析的promise,并且向已解析的promise添加then回调只会导致您的回调被尽快调用(但是异步;例如, then在调用回调之前返回。

答案 1 :(得分:1)

所以,我发现了Web Workers,这是我使用它们的代码的第一个版本。

app.controller('MainCtrl', function($scope, $q) {

  function hugeProcess () {
    var i = 0;
    var start = new Date().getTime();
    while (i++ < 100000) {
      console.log(i);
    }
    var end = new Date().getTime();
    var time = end - start;
    postMessage(time);
  }

  var blob = new Blob(["onmessage = " + hugeProcess.toString()]);

  // Obtain a blob URL reference to our worker 'file'.
  var blobURL = window.URL.createObjectURL(blob);
  var worker = new Worker(blobURL);

  worker.onmessage = function (message) {
    $scope.processTime = 'Done in ' + message.data  + 'ms';
    $scope.$apply()
  };

  $scope.onClickStartHugeProcessWithPromise = function () {
    console.debug('onClickStartHugeProcessWithPromise');
    $q(function () {
      worker.postMessage(''); // Start the worker.
    });
  };
});

我认为我没有正确使用它但是我做了我想要的...我发现Angular的包ng-webworker似乎混合了承诺和网络工作者,所以这正是我的意思寻找。

谢谢大家的帮助。

答案 2 :(得分:0)

Web Worker是正确的解决方案。我有类似的问题并开发了角度插件ng-vkThread来简化这类任务。

基本用法是:

/* function to execute in a thread */
function foo(n, m){ 
    return n + m;
}

/* create an object, which you pass to vkThread as an argument*/
var param = {
   fn: foo      // <-- function to execute
   args: [1, 2] // <-- arguments for this function
};

/* run thread */
vkThread.exec(param).then(
   function (data) {
       console.log(data);  // <-- thread returns 3 
    },
    function(err) {
        alert(err);  // <-- thread returns error message
    }

);

Live demo

- 瓦迪姆