角度js,广播事件并等待它完成

时间:2015-11-13 18:38:50

标签: javascript angularjs

我有一个像这样的角度事件:

$rootScope.$broadcast("postData");
doSomething();

但是,doSomething()必须等待postData在执行之前完成。 我通常会这样做:

$rootScope.$broadcast("postData").then(function(){
    doSomething();
});

但显然这不是一个有角度的东西......任何想法?

4 个答案:

答案 0 :(得分:5)

我想指出,在我们没有处理异步调用以处理回调/ promise / throw事件来解决问题的情况下,以前的解决方案是不可能实现的。异步调用可能是库函数,例如setTimeout,我们只是不能使用以前的解决方案来修复流程。

这是我的解决方案:

把doSomething();在setTimeout中,时间间隔设置为0,

$rootScope.$broadcast("postData");
setTimeout(function(){ 
    doSomething();}
, 0);

就这么简单!

settimeout使dosomething()也是异步的,这使得异步操作一个接一个地发生(异步)。怎么样?下面是解释,但首先请注意dosomething()的间隔为0毫秒的setTimout。人们可能会认为dosomething()应该在广播和服务之前立即执行(在0毫秒之后(实际上javascript中的默认最小时间间隔为4毫秒,因此0毫秒变为4毫秒))。 / p>

答案是否定的!

Settimeout不保证其中的回调函数passe必须在指定的时间间隔后执行。指定的时间间隔只是可以执行回调所需的最小时间间隔。 SetTimeOut是一个异步调用。如果已经在管道中等待任何其他异步操作,则javascript首先运行它们。

要了解这一切是如何发生的,您需要了解javascript中的事件循环。

Javascript运行时是单线程的,它只有一个调用堆栈,这意味着它在编写时按顺序运行代码。那它究竟是如何实现异步性的呢?

因此,当javascript运行时遇到异步操作(如API调用,http调用,settimeout,事件广播等)时,会发生这种情况。请注意我们的本机javascipt运行时引擎(例如chromes V8引擎)中没有提供这些功能,而是由浏览器(称为webAPI)提供,它们基本上是您可以调用的线程,它们分叉独立的执行路径,与javascript运行时执行流分开,这就是实际实现并发的方式。

问题出现了Javascript运行时仍然是单线程的。那么这些webAPI如何影响运行时流程并在完成后提供结果呢?他们不能只是在完成后随时提示javascript运行时并向其提供结果吗?必须有一些机制。

所以javascript只是调用这些webAPI而不等待调用的输出。它只是继续并执行调用之后的代码,这就是问题中的dosomething()如何在监听和服务postDate事件之前执行。

同时,分叉线程处理http调用或setTimeout或处理事件等,无论进行异步调用。完成后,将回调推送到事件队列(任务队列)(请注意,可以将多个回调返回到此队列中)。但他们不会马上跑。

javascript运行时等待调用堆栈首先变为空。当javascript运行时没有任何东西可以执行异步调用时,会逐个从任务队列中弹出回调函数并执行。

因此,实质上如果我们可以只使dosomething()异步,它将在第一次异步完成后执行。多数民众赞成我所做的。 settimeout回调被推送到事件队列/任务队列。 Javascript调用堆栈变空。 postData事件广播的回调得到了服务。然后dosomething()有机会执行。

答案 1 :(得分:4)

您可以$broadcast该事件,在其他控制器中使用$on进行侦听,然后在$emit完成另一个事件,并在原始控制器中进行侦听,以便了解何时它完成了。

我不推荐这种方法。而是使用服务。

Emit和broadcast正在将您的通信机制耦合到视图,因为$ scope基本上是数据绑定的结构。

服务方法更易于维护,除了控制器之外,还可以在服务之间进行通信。

答案 2 :(得分:1)

我假设广播'postData'正在定义一个功能的结束。

如果使用$ q angular服务,可以通过创建异步函数轻松完成。

function postData() {
  var deferred = $q.defer();

  //Do your asynchronous work here that post data does

  //When the asynchronous work is done you can just resolve the defer or
  //you can return data with resolve. Passing the data you want
  //to return as a param of resolve()
  deferred.resolve();

  //return
  return deferred.promise;
}

现在调用postData时,现在可以使用then方法在postData()完成后运行doSomething()。

 postData().then(function(data) {
    doSomething();
  }, function (err){
     //if your ansyncronous function return defer.reject() instead of defer.resolve() you can catch the error here
  };

这是$ q的角度documentation

继续向你展示一个简单的example

答案 3 :(得分:0)

这不是事件的工作方式,您不能等待事件完成。

为什么不解雇'postData',让这个事件的消费者做他们做的任何事情,然后等待另一个事件并在收到后执行'doSomething'?

这样,一旦'postData'的消费者完成了对事件的处理,他就可以触发你可以消费的另一个事件,并在你收到它时执行'doSomething'。