我有一个像这样的角度事件:
$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"。