ZephJS > Services
A common need when using ZephJS is to define functional services to work with your components. In this approach a component provides the view of the data and the service provides the data itself.
Initially ZephJS had a simple service registry layer which would allow one to couple a service to a given name, and then various ZephJS components could request the service and use it. Ultimately this was overkill for ZephJS and it was removed. However, services are still a big part of application development and ZephJS provides some support for using that paradigm.
Let us describe services by using a simple example: suppose we wanted to write a service that would provide the current time but only notify the component when the minute changes, instead of some fixed amount of time like every 100 milliseconds.
This entire example can be found here: BasicService Example
Here is our entire ClockService, which emits an "updated" event every minute (Every 60000 milliseconds) as close to the minute change as the JavaScript execution queue will allow.
import {ZephService} from "./Zeph.js";
const $FREQUENCY = Symbol("frequency");
const $NEXT = Symbol("next");
const $TIME = Symbol("time");
class ClockService extends ZephService {
constructor() {
super();
this[$NEXT] = null;
this[$TIME] = Date.now();
this.frequency = 60000;
}
get frequency() {
return this[$FREQUENCY];
}
set frequency(n=60000) {
n = parseInt(n,10);
if (n && !isNaN(parseInt(n))) this[$FREQUENCY] = n;
this.update();
}
get time() {
return this[$TIME];
}
update() {
if (this[$NEXT]) clearTimeout(this[$NEXT]);
this[$NEXT] = null;
let time = Date.now();
this[$TIME] = ((time/this.frequency)|0)*this.frequency;
let next = this[$TIME]+this.frequency-Date.now();
this[$NEXT] = setTimeout(this.update.bind(this),next);
this.fire("updated",this[$TIME]);
}
}
const instance = new ClockService();
export {instance as ClockService};
We start, by importing ZephService from ZephJS. ZephService provides all the event firing and event handling functionality that we need.
import {ZephService} from "./Zeph.js";
Read more about ZephService's API below.
Next, we create a new class, ClockService, that extends ZephService. The only trick to this is that in our constructor()
method we need to call super()
.
class ClockService extends ZephService {
constructor() {
super();
...
}
...
}
Otherwise, our service can do whatever it wants. In our case we are setting up a timer to execute at the top of every minute. This in turn updates the time and fires our "updated" event.
this.fire("updated",this[$TIME]);
The final thing to do with a service is to export it. In most cases you want to export a singleton of the service, thus you must first create that instance and then export that as the given name of your service. This is shown in the last two lines of our sample code:
const instance = new ClockService();
export {instance as ClockService};
Once you have created a service as described above, using it in your code is as simple as importing it:
import {ClockService} from "./ClockService.js";
We can then use the service however we wish, such as asking for the time:
let time = ClockService.time;
Whatever you expose in your class as a getter, setter, or method, is available to the service consumer. Additionally, the service consumer can register listeners with addEventListener()
, on()
, or once()
, or remove event listeners with removeEventListener()
or off()
.
ZephService provides the scaffolding your service will need to emit and handle events. This includes
fire(eventName, ...args)
For emitting an event of the given name with any number of arguments.
addEventListener(eventName, listener)
Add a listener for a given event name.
removeEventListener(eventName, listener)
Remove a listener for a given event name.
on(eventName, listener)
The same asaddEventListener()
. Provided for convenience.
once(eventName, listener)
A special case ofaddEventListener()
, this will fire once for a given event and then remove itself.
off(eventName, listener)
The same asremoveEventListener()
. Provided for convenience.