我有一个像这样的角度事件:
$rootScope.$broadcast("postData");
doSomething();
但是,doSomething()必须等待postData在执行之前完成。 我通常会这样做:
$rootScope.$broadcast("postData").then(function(){
doSomething();
});
但显然这不是一个有角度的东西......任何想法?
答案 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'。