Javascript 播放一个事件并等待它完成

Javascript 播放一个事件并等待它完成,javascript,angularjs,Javascript,Angularjs,我有一个像这样的角度事件: $rootScope.$broadcast("postData"); doSomething(); 但是,doSomething()必须等待postData完成后才能执行。 我通常会这样做: $rootScope.$broadcast("postData").then(function(){ doSomething(); }); 但很明显,这不是一个角度的问题……有什么想法吗?这不是事件的工作方式,你不能等待事件完成 为什么不启动“postData”,让此

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

$rootScope.$broadcast("postData");
doSomething();
但是,doSomething()必须等待postData完成后才能执行。 我通常会这样做:

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

但很明显,这不是一个角度的问题……有什么想法吗?

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

为什么不启动“postData”,让此事件的消费者做他们所做的任何事情,然后等待另一个事件并在收到它后执行“doSomething”


这样,一旦“postData”的使用者完成了对事件的处理,他就可以触发另一个事件,您可以在收到该事件时使用该事件并执行您的“doSomething”。

您可以
$broadcast
该事件,在另一个控制器中使用
$on
收听该事件,并在完成时
$emit
另一个事件,在你原来的控制器中聆听它,这样你就知道它什么时候完成了

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

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


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

Im假设“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时,可以在postData()完成后使用then方法运行doSomething()

这是$q的角度


下面是一个简单的例子

,我想指出,如果我们没有异步调用的句柄来放置回调/承诺/抛出事件来解决问题,那么之前的解决方案是不可能实现的。异步调用可能是库函数,例如setTimeout,我们不能使用以前的解决方案来修复流

以下是我的解决方案:

放一些东西();在时间间隔设置为0的setTimeout中

$rootScope.$broadcast("postData");
setTimeout(function(){ 
    doSomething();}
, 0);
就这么简单

settimeout使dosomething()也是异步的,这使两个异步操作一个接一个地(异步地)发生。怎么用?解释如下,但首先要注意dosomething()的设置时间间隔为0毫秒。人们可能会明显认为,在postData事件广播和服务之前,应该立即执行dosomething()(0毫秒之后(javascript中的默认最小时间间隔为4毫秒,因此0毫秒变为4毫秒))

答案是否定的

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()有机会执行。

在调用
$rootScope.$broadcast('postData',dosomething')
之前,尝试添加
$rootScope.$broadcast('postData')
。这为postData事件添加了一个侦听器,并在检测到该事件时执行doSomething。我不太理解“doSomething()必须等待postData完成才能执行”。postData是一个事件,而不是一个函数。你的意思是想在触发doSomething之前等待连接到该事件的所有侦听器完成吗?@igorshmigor这是正确的。你不明白。你的例子是正确的,但不是他所要求的。他在子控制器doSomethin中有postData()
$rootScope.$broadcast("postData");
setTimeout(function(){ 
    doSomething();}
, 0);