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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33699679/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 16:49:01  来源:igfitidea点击:

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

javascriptangularjs

提问by user3689167

I have a an angular event like this:

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

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

however, doSomething() must wait for postData to complete before execution. I would normally do something like:

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

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

But apparently this isn't a thing in angular...Any ideas?

但显然这不是角度的东西......有什么想法吗?

回答by Pradeep Jain

I would like to point-out that the previous solutions are not possible to be implemented where we don't have a handle on the async call to put a callback/promise/throw an event to solve the issue. The async call may be library function like for example setTimeout and we just cant use the previous solutions to fix the flow.

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

Here's my solution:

这是我的解决方案:

Put doSomething(); in an setTimeout with the time interval set to 0,

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

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

As simple as that!

就如此容易!

settimeout makes dosomething() also to be asynchronous and this makes both the asynchronous operations happen one after the other(asynchronously). How? The explanation follows, but first note that the dosomething() is in a setTimout of interval 0 ms. One may obviously think that dosomething() shall be executed right-away (after 0 ms (actually default minimum time interval in javascript is 4 ms, so 0 ms becomes 4 ms)) before the postData event is broadcast-ed and serviced.

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

The answer is no!

答案是不!

Settimeout doesn't guarantee that the callback function passe inside it shall surely get executed after the specified interval. The specified interval is just the minimum interval needed after which the callback can be executed. SetTimeOut is an asynchronous call. if there are any other async operation waiting in the pipeline already, javascript runs them first.

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

For understanding how all this happen you need to understand what is an event loop in javascript.

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

Javascript runtime is single threaded, it just have one call stack, meaning it runs the code sequentially as it is written. Then how on earth does it implement asyncronicity?

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

So this is what happens under the hood when the javascript run-time encounters an operation that is asyncronous (like an API call, http call, settimeout, event broadcast etc). Please note these functions are not provided in our native javascipt run time engine (for example chromes V8 engine), instead they are provided by the browser (known as webAPIs), which are basically threads that you can make call to and they fork off an independent path of execution, separate from the javascript run-time execution flow, and thats how concurrency is actually achieved.

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

The question arises that Javascript run time is still single threaded. So how does these webAPI inturrpt the runtime flow and provide their results when they are complete? They can not just prompt the javascript runtime anytime when they are finished and provide their results to it? There must be some mechanism.

问题出现了 Javascript 运行时仍然是单线程的。那么这些 webAPI 如何干扰运行时流程并在它们完成时提供它们的结果呢?他们不能在完成后随时提示 javascript 运行时并将结果提供给它吗?一定有什么机制。

So javascript just makes the call to these webAPI's and does not wait for the output of the call. It simply goes on and execute the code that follows the call, and thats how the dosomething() in the problem, gets executed before the postDate event is listened and served).

因此 javascript 只是调用这些 webAPI 而不会等待调用的输出。它只是继续执行调用之后的代码,这就是问题中的 dosomething() 在侦听和服务 postDate 事件之前执行的方式)。

Meanwhile the forked thread processes the http call or the setTimeout or handle the event etc, whatever the async call was made for. And when its done, the callback is pushed onto a event queue (task queue) (Note that multiple callback returns can be pushed into this queue.). But they are not run right away.

同时,分叉线程处理 http 调用或 setTimeout 或处理事件等,无论异步调用是为了什么。当它完成时,回调被推送到一个事件队列(任务队列)(注意,多个回调返回可以被推送到这个队列中。)。但他们不会立即逃跑。

The javascript runtime waits for the call stack to get empty first. When there is nothing for the javascript runtime to execute the async calls callback function are popped out from the task queue, one by one and executed.

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

So in essence if we can just make dosomething() async, it will get executed after the 1st async is completed. Thats what I did. The settimeout callback gets pushed onto the event queue/task queue. Javascript call stack gets empty. The call back for postData event broadcast gets served. Then dosomething() gets a chance to execute.

所以本质上,如果我们可以让 dosomething() 异步,它将在第一个异步完成后执行。这就是我所做的。settimeout 回调被推送到事件队列/任务队列。Javascript 调用堆栈变空。postData 事件广播的回调得到服务。然后 dosomething() 有机会执行。

回答by Tristan

You could $broadcastthe event, listen for it in your other controller with $on, and $emitanother event on completion, and listen for it in your original controller so you know when it is finished.

你可以$broadcast的情况下,听它在您与其他控制器$on,并$emit在完成另一个事件,并在原来的控制器监听,所以你知道什么时候结束。

I would not recommend this approach. Instead use a service.

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

Emit and broadcast are coupling your mechanisms for communication to the view because the $scope is fundamentally a fabric for data-binding.

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

The services approach is far more maintainable and can communicate between services in addition to controllers.

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

回答by jkerb

Im assuming the broadcast of 'postData' is defining the end of a funciton.

我假设“postData”的广播定义了函数的结尾。

If you use the $q angular service this can be accomplished easily by creating asynchronous functions.

如果您使用 $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;
}

When you call postData now you can now use the then method to run doSomething() after postData() is done.

当您现在调用 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
  };

Heres the angular documentationfor $q

这是 $q的角度文档

Heres a plunk to show you a simple example

这是一个 plunk 向您展示一个简单的例子

回答by AdirAmsalem

This isn't how events works, you can't wait for events to complete.

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

Why won't you fire 'postData', let the consumers of this event do whatever they does, and then wait for another event and execute 'doSomething' once you receive it?

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

This way, once the consumer of 'postData' finish processing the event, he can fire another event which you can consume and execute your 'doSomething' when you receive it.

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