I have little nooby question about event emitter but it is really important for may program logic.
I am using some external library that fires events I am listening. Lets say it fires 2 events : 'data' and 'error'. Lets say that lib will always call data before error, something like this:
emit('data', 'some data');
emit('error', 'some error');
Question is: can I be 100% sure that data event will always come before error event in my listen methods?:
lib.on('data', function(data) {
// is this always first
});
lib.on('error', function(error) {
// or maybe this
});
Thanks,
Ivan
The EventEmitter emit function is a synchronous blocking function. And hence, like any other blocking function, it is guaranteed to execute in the exact order it is called in.
Related
So I ran into some Javascript weirdness if i write a function like this my passed callback works fine
messageHandler(callback) {
this.ws.onmessage = (data) => {
callback(data.data);
};
}
If you write like this
messageHandler(callback) {
this.ws.on('message', (data) => {
callback(data);
});
}
It mutates the callback into a message event I can't seem to figure out why but I'd like to understand this behavior if anyone can explain. Thanks in Advance.
I think the question omits crucial information but based on the code examples, I think you're using https://github.com/websockets/ws implementation, correct?
If so, then .ws.on('message', ... refers to Event Emitter listener. The params passed to your handler is the message or stream or whatever data object the emitter emits.
.ws.onmessage refers to the browser's Websocket API - so the parameter passed there is a MessageEvent. As you can see from the spec, data is a property on MessageEvent class which explains why you have to refer with 1 level of indirection as data.data.
Perhaps it'd be less confusing if you call your parameter event instead of data in the first example:
this.ws.onmessage = (event) => {
callback(event.data);
};
You can also view this as server side events vs. client side events - your first example is a client side event whereas the second example is a server side event. Client side events conform to Websockets API whereas server side events, in NodeJS world, typically use event emitters.
I have a question about chrome extension install/update event. If I add the onInstalled event listener in a top level code in the background script, is there a time frame in which my event listener will catch that event?
I'm asking this, because my demos showed that if I have some logic that executes before I hook onInstalled listener, it looks like it will never be executed, like that event happens in the meantime.
Can someone explain to me with more details how this event works, in the context of other logic in the background script, or point me to some documentation, since I haven't been able to find anything useful.
Thanks!
Update #Noam Hacker : Due to a company policy I can't post any real code here, but I have some pseudo code that illustrates my problem :
/**
* setup in which I miss onInstalled event
*/
function firstLogicThatRunsOnBackgroundLoad() {
// perform some logic
// perform some asynchronous operations via generators and promises
// which can take a while
chrome.runtime.onInstalled.addListener(function (details) {
if (details.reason == "install") {
// this logic never gets executed
} else if(details.reason == "update") {
// perform some logic
}
});
}
/**
* setup in which I catch onInstalled event
*/
function firstLogicThatRunsOnBackgroundLoad() {
chrome.runtime.onInstalled.addListener(function (details) {
if (details.reason == "install") {
// this logic executes
} else if(details.reason == "update") {
// perform some logic
}
});
// perform some logic
// perform some asynchronous operations via generators and promises
// which can take a while
}
onInstalled listeners catch events in these situations:
when the extension is first installed, when the extension is updated to a new version, and when Chrome is updated to a new version.
Since this is all asynchronous it will happen in the background, and according the documentation, fires immediately at any of these situations. Review asynchronous programming for some clarity on this.
link to documentation
According to your question it seems like you want help executing code in the right order. This answer provides a helpful framework for your case (using the reason attribute).
chrome.runtime.onInstalled.addListener(function(details){
if(details.reason == "install"){
//call a function to handle a first install
}else if(details.reason == "update"){
//call a function to handle an update
}
});
I needed to figure this out too. While I didn't find anything authoritative, I did throw a couple of console.time() statements in my background script.
Code was something like this:
console.time('onInstall event');
console.time('first function');
chrome.runtime.onInstalled.addListener(details => {
console.timeEnd('onInstall event');
});
// 7 module imports
someSyncFunction() // console.timeEnd('first function') is called in the first line in this function
Then I just loaded/reloaded the extension (unpacked, in dev mode) a few times. onInstall seems to pretty reliably fire within the first 50ms, while the first function happens w/in the first ms. Here are the results:
(First function, onInstall event)
(.282ms, 47.2ms)
(.331ms, 45.3ms)
(.327ms, 49.1ms)
(.294ms, 45.9ms)
Given that the document says
“Listeners must be registered synchronously from the start of the page.”
and
“Do not register listeners asynchronously, as they will not be properly triggered.”
, it seems they guarantee every synchronously-attached listener not to miss any, no matter how long it takes to evaluate your code. And this would be done by Chrome firing events after evaluating your entire code.
My hypothesis is that onInstalled actually works like onInitialized. No test data, though.
I'm new to backbone. I have been looking it has been used in Saiku. I came across the below line.
Saiku.session.trigger('workspace:new', { workspace: this });
Is 'workspace:new' an event? How does backbone trigger recognize it as an event?
Short answer: yes, workspace:new is an event.
Backbone has several built-in events that you can listen for. But you can also trigger custom events, as this code does. The event is identified by only a string (in this case, "workspace:new"). When you call trigger on an object that inherits from Backbone's Event Module, that event "happens." As a second parameter to trigger, you can pass some data about the event, anything you want accessible from the event handler function.
Then, usually somewhere else, there will be code waiting for that event to happen. That is set up by calling the .on or .listenTo methods.
Here's a basic example: (See it in action on JSBin)
var model = new Backbone.Model();
model.on('my-event', function (data) {
console.log("my-event happened!");
console.log(data);
});
model.trigger('my-event');
model.trigger('my-event', 'some-data');
model.trigger('my-event', { anything: 'works' });
My requirements
Because of the asynchronous architecture of my applications I am looking for an 'event' system which has the following two two properties:
The events should be able to fire multiple times (possible with events, but not with promises)
When I start listening for an event that has already been fired, I want the listener to fire once immediately (as with promises)
The reason for 1. is that there are a lot of events (e.g. the updating of certain data) that I want to be able to fire multiple times. But I would like to combine this with 2. so that if an event has already fired upon adding the listener, this listener gets called immediately. This is because I'm not always sure (and I don't want to be sure) which piece of code gets run first.
My 'solution'
I have thought up the following solution. I'm using this in an AngularJS application therefore the AngularJS context, but the question is applicable for Javascript in general. Note that I simplified the code.
app.controller('AppCtrl', function(CustomEventEmitter){
// Broadcast an event. No listener added so nothing happens
CustomEventEmitter.broadcast('event');
// Add the event listener. Because the event allready fired, the listener gets called immediatly
CustomEventEmitter.on('event', function(){
console.log('Event emitted');
});
// Broadcast an other event
CustomEventEmitter.broadcast('event');
});
app.service('CustomEventEmitter', function(){
var
listeners = {},
memory = [];
this.broadcast = function(name){
// The normal broadcasting of the event to the listener
if(listeners[name]) {
listeners[name].forEach(function(listener){
listener();
});
}
// Push the event into the 'memory'
memory.push(name);
};
this.on = function(name, listener){
// The normal adding of the listener
if(!listeners[name]) {
listeners[name] = [];
}
listeners[name].push(listener);
// If an event is already in memory, call the listener
if(memory.indexOf(name) !== -1) {
listener();
}
};
});
My questions
My questions are these:
What is the 'best practice' solution for my requirements?
What do you think of my 'solution'?
Am I missing something completely obvious?
The reason for the last question is that it seems to me that this is a very common design paradigm but I seem unable to find the best way to solve this in simple and concise way.
Note
I understand this can be solved with the adding of extra code (e.g. before adding the listener, check in an other way if the event you are going to listen for already happened) but this is not what I'm looking for.
A "property" from bacon.js does exactly what you are asking for. This falls under the broader category of functional reactive programming (FRP). The most popular two libraries for this in JavaScript are probably
bacon.js
Reactive Extensions
Both of which provide the specific tool you're asking for, along with a vast array of alternatives.
I've written happily a node.js server, which uses socket.io to communicate with the client.
this all works well.
the socket.on('connection'...) handler got a bit big, which made me think of an alternative way to organize my code and add the handlers in a generator function like this:
sessionSockets.on('connection', function (err, socket, session) {
control.generator.apply(socket, [session]);
}
the generator takes an object that contains the socket events and their respective handler function:
var config = {
//handler for event 'a'
a: function(data){
console.log('a');
},
//handler for event 'b'
b: function(data){
console.log('b');
}
};
function generator(session){
//set up socket.io handlers as per config
for(var method in config){
console.log('CONTROL: adding handler for '+method);
//'this' is the socket, generator is called in this way
this.on(method, function(data){
console.log('CONTROL: received '+method);
config[method].apply(this, data);
});
}
};
I was hoping that this would add the socket event handlers to the socket, which it kind of does, but when any event comes in, it always calls the latest one added, in this case always the b-function.
Anyone any clues what i am doing wrong here?
The problem appears because by that time this.on callback triggers (let's say in a few seconds after you bind it), the for loop is finished and method variable becomes the last value.
To fix that you may use some JavaScript magic:
//set up socket.io handlers as per config
var socket = this;
for(var method in config){
console.log('CONTROL: adding handler for '+method);
(function(realMethod) {
socket.on(realMethod, function(data){
console.log('CONTROL: received '+realMethod);
config[realMethod].apply(this, data);
});
})(method); //declare function and call it immediately (passing the current method)
}
This "magic" is hard to understand when you first see it, but when you get it, the things become clear :)