angular js,广播一个事件并等待它完成

angular js, broadcast an event and wait for it to complete

本文关键字:事件 等待 一个 js 广播 angular      更新时间:2023-09-26

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

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

但是,doSomething()必须等待postData完成后才能执行。我通常会做这样的事情:

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

但显然这不是一件有棱角的事情。。。有什么想法吗?

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

这是我的解决方案:

做某事();在时间间隔设置为0的setTimeout中,

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

就这么简单!

settimeout使得dosomething()也是异步的,这使得两个异步操作一个接一个地(异步)发生。怎样解释如下,但首先要注意的是,dosomething()处于间隔为0毫秒的setTimout中。人们可能会明显地认为,在postData事件被广播和服务之前,dosomehing()应该立即执行(在0毫秒之后(实际上javascript中默认的最小时间间隔是4毫秒,所以0毫秒变成4毫秒)。

答案是否定的!

Settimeout并不保证它内部传递的回调函数一定会在指定的时间间隔后执行。指定的间隔只是执行回调所需的最小间隔。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()有机会执行。

您可以$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()。

 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 的角度文件

这里有一个plunk向您展示一个简单的示例

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

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

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