In Dart, if I listen to a click event with two listeners, how do I know which happens first? - dart

If I write the following Dart code, how do I know which click handler happens first?
main() {
var button = new ButtonElement();
var stream = button.onClick.asBroadcastStream();
stream.listen(clickHandler1);
stream.listen(clickHandler2);
}
Let's say I'm in other code that doesn't know anything about the first two click handlers, but I register another one.
Can I know that the stream has two listeners?
Can I pause or cancel all other subscribers?
If I write button.onClick.asBroadcastStream() again elsewhere, does it point to the same stream as was used in main?
Can I say in one of the handlers to not pass event on to the other broadcast listener? Is that a consumer?

Let's say I'm in other code that doesn't know anything about the first
two click handlers, but I register another one.
Can I know that the stream has two listeners?
No, you can't. You could extend the stream class or wrap it and provide this functionality yourself, but it does not feel like a good design choice, because I don't think a listener should know about other listeners. What are you trying to do exactly? Perhaps there's a better way than letting listeners know about each other.
Can I pause or cancel all other subscribers?
You can cancel/pause/resume only the subscriber you are dealing with. Again, you probably shouldn't touch other listeners, but I guess you could wrap/extend the Stream class to have this behavior.
If I write button.onClick.asBroadcastStream() again elsewhere, does it point to the same stream as was used in main?
No, at least not at the current version of SDK. So, unfortunately, you need to store a reference to this broadcast stream somewhere, and refer to it, because calling asBroadcastStream() multiple times will not yield in the result you might expect. (Note: at least based on quick testing: http://d.pr/i/Ip0K although the documentation seems to indicate different, I have yet to test a bit more when I find the time).
Can I say in one of the handlers to not pass event on to the other broadcast listener?
Well, there's stopPropagation() in the HTML land which means that the event won't propagate to other elements, but it's probably not what you were looking for.
For being able to stop an event firing in other listeners, there needs to be an order of which the listeners are getting called. I believe the order is the order of registration of those listeners. From the design perspective, I don't think it would be a good idea to allow a listener to cancel/pause others.
Event propagation in HTML makes sense since it's about hierarchy, but here we don't have that (and even in case of events in HTML there can be multiple listeners for the single element).
There's no way to assign weight to listeners or define the order of importance, therefore it's not surprising that there isn't a way to stop the event.
Instead of letting listeners know about each other and manipulate each other, maybe you should try to think of another way to approach your problem (whatever that is).
Is that a consumer?
The StreamConsumer is just a class that you can implement if you want to allow other streams to be piped into your class.

Can I know that the stream has two listeners?
No, you have a ´Stream´ that wraps the DOM event handling. There is no such functionality.
Can I pause or cancel all other subscribers?
Look at Event.stopPropagation() and Event.stopImmediatePropagation(), and possibly Event.preventDefault().
If I write button.onClick.asBroadcastStream() again elsewhere, does it point to the same stream as was used in main?
[Updated] No, the current implementation doesn't gives you the same Stream back since the onClick getter returns a new stream every time it is invoked. However, the returned stream is already a broadcast stream so you shouldn't invoke asBroadcastStream() on it. If you do you will hower just get a reference to the same object back.
Stream<T> asBroadcastStream() => this;
Can I say in one of the handlers to not pass event on to the other broadcast listener? Is that a consumer?
Again, take a look at Event.stopPropagation() and Event.stopImmediatePropagation(), and possibly Event.preventDefault().

Related

Synchronization in ActionScript

Despite my best efforts, I am unable to produce the kind of synchronization effects I would like to in ActionScript. The issue is that I need to make several external calls to get various pieces of outside information in response to a user request, and the way items will be laid out on the page is dependent on what each of these external calls returns. So, I don't care that all of these calls return asynchronously. However, is there any way to force some amount of synchronization on ActionScript, so that at least calling the method for doing the final layout and placement of items on the page is dependent on all of my calls finishing?
If I understand the question right, event listeners are probably your best bet. Most loader classes throw an Event.COMPLETE message when they finish doing everything behind the scenes. If you wrote those external calls, it would be easy to dispatch a complete event at the end.
So when you make all these external calls, have a function that listens to when those calls complete. This function would keep track of how many calls have been made, and when there's none left to run, continue building your layout.
Rough Sketch to explain below:
var numProcesses:int = 0;
slowthing.addEventListener(Event.COMPLETE,waitForSlowest);
numProcesses++;
slowthing.load();
quickThing.addEventListener(Event.COMPLETE,waitForSlowest);
numProcesses++;
quickthing.load();
function waitForSlowest(e:Event)
{
numProcesses--;
if(numProcesses == 0)
finalizeLayout();
}

Can I handle any received message in gen_fsm state callbacks?

I noticed that messages sent to the pid of a gen_fsm process are matched in the state callbacks as events. Is this just accidental or can I rely on this feature?
Normally I would expect general messages sent to a gen_fsm to show up in the handle_info/3 callback and thought I would have to re-send it using gen_fsm:send_event.
Does gen_fsm try to match the message first to the state callback and then allways with the handle_info/3 callback? Or only if it doesn't match a state callback clause?
However when I try it my message seems to be handled twice according to debug output.
So basically the question can also be stated like: how to correctly handle received messages as events in gen_fsm state functions?
Clarification: that some of the events are occurring by getting messages passed should be considered given for this question.
I'm aware that in many cases its cleaner to make the protocol visible by using function calls into the fsm only.
I'm not so sure if this would improve the current framework where the mentioned gen_fsm has to fit in: Diverse protocol stacks where each layer calls a connect() function to attach (and sometimes start) the lower layer. Packets are sent to lower layers ba calling a function (send) and received by receiveing a message. Much like gen_tcp.
By looking at the code for gen_fsm I already figured out that general messages are only passed to handle_info, so only the question remains wether to call the state function directly from the handle_info/3 callback or resent using gen_fsm:send_event.
General messages are handled by handle_info callback, unless you have something like this in your code:
handle_info(Info, StateName, StateData) ->
?MODULE:StateName(Info, StateData).
Which avoids resending, but I do not recommend neither that, nor resending.
Delivering events exclusively by means of API calls encapsulating send_event/sync_send_event/send_all_state_event/sync_send_all_state_event makes protocol explicit. Which is a right thing, as it is easier to understand, maintain and document with edoc.

State in OTP event manager process (not handler!)

Can an OTP event manager process (e.g. a logger) have some state of its own (e.g. logging level) and filter/transform events based on it?
I also have a need to put some state into the gen_event itself, and my best idea at the moment is to use the process dictionary (get/put). Handlers are invoked in the context of the gen_event process, so the same process dictionary will be there for all handler calls.
Yes, process dictionaries are evil, but in this case they seem less evil than alternatives (ets table, state server).
The gen_event implementation as contained in the OTP does no provide means for adding state.
You could extend the implementation to achieve this and use your implementation instead of gen_event. However I would advise against it.
The kind of state you want to add to the event manager belongs really in the event handler for several reasons:
You might want to use different levels in different handlers, e.g. only show errors on the console but write everything to the disk.
If the event level would be changed in the manager event handlers depending on getting all unfiltered events might cease to function (events have more uses than just logging). This might lead to hard to debug problems.
If you want a event manager for multiple handlers that all only get filtered events you can easily achieve this by having two managers: one for unfiltered messages and one for e.g. level filtered messages. Then install a handler to the unfiltered one, filter in the handler by level (easy) and pass on the filtered events to the other manager. All handlers that only want to get filtered messages can be registered to the second manager.
The handlers can have their own state that gets passed on every callback like:
Module:handle_event(Event, State) -> Result
Filtering might look like this (assuming e.g. {level N, Content} events):
handle_event({level, Lvl, Content}, State#state{max_level=Max}) when Lvl >= Max ->
gen_event:notify(filtered_man, Content);
The State can be changed either by special events, by gen_event:call\3,4 (preferably) or by messages handled by handle_info.
For details see Gen_Event Behaviour and gen_event(3)
When you start_link a gen_event process - thing that you should always do via a supervisor -, you can merely specify a name for the new process, if you need/want it to be registered.
As far as I can see, there's no way to initiate a state of some sort using that behaviour.
Of course, you can write your own behaviour, on the top of a gen_event or of a simple gen_server.
As an alternative, you might use a separate gen_event process for each debugging level.
Or you can just filter the messages in the handlers.

How do you unwire an action in Nitrogen?

In Nitrogen, the Erlang web framework, you wire actions like this:
wf:wire(send_message, #event { type=click, postback=send_message })
but if after that you run
wf:wire(send_message, #event { type=click, postback=send_message2 }),
then you get the action wired twice.
How do you unwire the previous action or all actions of an element?
Since events in nitrogen are bound using jquery's bind method. You can use unbind to unbind them. There isn't currently a nitrogen api to unbind an event but you could output the javascript code to unbind it yourself if you so wished.
see action_event.erl for an example of how the binding javascript is output. You can create a similar action/event that removes the binding.
I too was looking for an "unwire" and didn't find it. My work-around was to wf:replace() the element to which the event was wired, and wire the replacement element; I hope that javascript will eventually notice the former bind can never be called and then garbage collect it. I don't know how expensive such abandoned bindings are. My context was a lazy loading of the page, such that a button would initially show a stub, but when clicked would download arbitrarily large content, and henceforth toggle hide/show.
Beyond being nervous about the sophistication of the javascript garbage collection, I'm worried that this may be a bad pattern, and would love to hear others' experience. The only alternative that occurs to me would be to keep state (e.g. data) in the original element and pass that state back with the event message so that the same event handler would act on the "unloaded->loaded_show->loaded_hide->loaded_show" transitions. But I'd prefer not to be calling back to the server for a simple hide/show transition.

Can a 'while loop' be used in actionscript to monitor an event dispatch?

I am creating an action script library.I am calling some APIs which parses some xml and gets me the result. It dispatches an Event.COMPLETE when the parsing is done. I want to monitor whether this event is dispatched in some while loop like "while(eventnotdispatched)"
is it possible? I know the other way would be to addeventlistener. But please let me know if the other thing is possible.
Thanks
NO, it is not possible. Actionscript is single threaded. Thus while you are waiting in your while loop, that is the only thread running, and the process you are waiting for can never complete. This is why everything is done with events, so that's what you should use. If you need to update your display periodically while you are waiting for something to complete...again, use events. Create a Timer object which generates a TIMER event every so often, and use that to make your updates.
EDIT: Davr is right, you would not be able to use the while loop like this. You would need a timer.
Yes, it is possible to poll for it. BUT you will still need to create an event listener. It will work something like this:
private var loadCompleted = false;
private var timer:Timer= new Timer(1);
private function onInitCompleted(event:Event):void
{
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.start();
}
private function loadCompleteEventHandler(event:Event):void
{
loadCompleted = true;
...
}
private function timerHandler()
{
if(!loadCompleted)
{
... // stop the timer or something.
timer.stop();
}
}
Please note, this is VERY BAD code. I would NEVER use it in production because Actionscript is a event driven language. There should be absolutely NO REASON for you to need to do this. Whatever you are trying to do could be accomplished using another method much simpler. Tell me what you are trying to accomplish with this and I will present a better solution.
Sorry for yelling, it's late and I am sleepy.
Doing that means forcing a synchronous model of execution on the underlying asynchronous model (that works with callbacks).
What are you trying to achieve exactly, and why not use a callback?
I agree with the statements about it probably being a bad idea and a while loop will certainly not work this way in ActionScript. However, there may be legitimate reasons for doing what you are attempting to do. Only you can prevent bad code. Instead of judging, I'll just get to an answer for your question.
First I'm going to make an assumption, that what you really want to do is monitor a property and for some reason the API for this object does not dispatch an event when this property changes. I'm making this assumption because if you have the event available, I assume you would just use the event.
So... you have an object weirdXmlObj with a property loaded that defaults to false but goes to true when the XML is loaded.
In this case with slight modifications the code posted by CookieOfFortune would in fact work. You wouldn't need the loadCompleteEventHandler function (which was never attached anyway) and in the timer handler you would simply check if( weirdXmlObj.loaded ) and then branch however you wanted to.
Ah but there may be a simpler way, depending on what you are doing.
If you have a display object handy. (i.e. something that makes sense, not just some random object.) You can attach your code to the stage's EnterFrame event instead of using a timer.
myDisplayObject.stage.addEventListner(Event.ENTER_FRAME,frameEnterHandler);
A couple of things to be aware of:
You don't really even need to go to the stage level, all display objects support the EnterFrame event, but it's a nice place to attach the event listener.
You really should keep whatever the function calls to a minimum. In particular the actual frameEnterHandler function should do nothing more than do the if( weirdXmlObj.loaded ) check.
You are attempting to circumvent event-driven programming, which is not a good idea. This is often the case when someone approaches from an older model and does not yet have a good frame of reference to appreciate the elegance of event-driven programming.
Events are your friends. They work very well. Your loadCompleteHandler is all that is required. Want to do something else in response? Add the call in that handler:
private function loadCompletedHandler(event:Event):void
{
waitingObject.fileWasLoadedSoGoDoThatThing();
}
There is no need to make it any more complicated than that. No need for a semaphore or a loop to check the semaphore. Unnecessary environmental semaphores can break the encapsulation that could shield you from unwanted side effects.

Resources