Skip to content

Latest commit

 

History

History
127 lines (85 loc) · 4.4 KB

Services.md

File metadata and controls

127 lines (85 loc) · 4.4 KB

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.

An Example

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};

Using a Service

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 API

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 as addEventListener(). Provided for convenience.

once(eventName, listener) A special case of addEventListener(), this will fire once for a given event and then remove itself.

off(eventName, listener) The same as removeEventListener(). Provided for convenience.