mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
feat(observable): Implement observable .once (#5309)
Node has a handy one-liner method on its EventEmitter called "once". It is similar to "on", but fires a single time and automatically unsubscribes.
This commit is contained in:
committed by
Alexander Vakrilov
parent
9d7f0e5315
commit
2166d1e415
@@ -95,6 +95,14 @@ export class Observable {
|
||||
*/
|
||||
on(event: "propertyChange", callback: (data: EventData) => void, thisArg?: any);
|
||||
|
||||
/**
|
||||
* Adds one-time listener function for the event named `event`.
|
||||
* @param event Name of the event to attach to.
|
||||
* @param callback A function to be called when the specified event is raised.
|
||||
* @param thisArg An optional parameter which when set will be used as "this" in callback method call.
|
||||
*/
|
||||
once(event: string, callback: (data: EventData) => void, thisArg?: any);
|
||||
|
||||
/**
|
||||
* Shortcut alias to the removeEventListener method.
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
interface ListenerEntry {
|
||||
callback: (data: EventData) => void;
|
||||
thisArg: any;
|
||||
once?: true;
|
||||
}
|
||||
|
||||
let _wrappedIndex = 0;
|
||||
@@ -56,6 +57,11 @@ export class Observable implements ObservableDefinition {
|
||||
this.addEventListener(eventNames, callback, thisArg);
|
||||
}
|
||||
|
||||
public once(event: string, callback: (data: EventData) => void, thisArg?: any) {
|
||||
const list = this._getEventList(event, true);
|
||||
list.push({ callback, thisArg, once: true });
|
||||
}
|
||||
|
||||
public off(eventNames: string, callback?: any, thisArg?: any) {
|
||||
this.removeEventListener(eventNames, callback, thisArg);
|
||||
}
|
||||
@@ -120,6 +126,9 @@ export class Observable implements ObservableDefinition {
|
||||
|
||||
for (let i = observers.length - 1; i >= 0; i--) {
|
||||
let entry = observers[i];
|
||||
if (entry.once) {
|
||||
observers.splice(i, 1);
|
||||
}
|
||||
if (entry.thisArg) {
|
||||
entry.callback.apply(entry.thisArg, [data]);
|
||||
} else {
|
||||
|
||||
61
unit-tests/observable/observable.ts
Normal file
61
unit-tests/observable/observable.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { Observable } from "tns-core-modules/data/observable";
|
||||
import { assert } from "chai";
|
||||
|
||||
describe("observable", () => {
|
||||
describe("once", () => {
|
||||
|
||||
let observable: Observable;
|
||||
let handler: () => void;
|
||||
let callCount: number = 0;
|
||||
|
||||
beforeEach("create handlers", () => {
|
||||
handler = function() {
|
||||
callCount++;
|
||||
}
|
||||
observable = new Observable();
|
||||
observable.once("test", handler);
|
||||
});
|
||||
afterEach("reset handlers", () => {
|
||||
callCount = 0;
|
||||
handler = null;
|
||||
observable = null;
|
||||
});
|
||||
|
||||
function notify() {
|
||||
observable.notify({ eventName: "test", object: observable });
|
||||
}
|
||||
function notifyWrong() {
|
||||
observable.notify({ eventName: "test2", object: observable });
|
||||
}
|
||||
|
||||
it("fires just once", () => {
|
||||
notify();
|
||||
notify();
|
||||
assert.equal(callCount, 1, "Expected the handler to be called exactly once");
|
||||
});
|
||||
it("does not fire for other events", () => {
|
||||
notifyWrong();
|
||||
assert.equal(callCount, 0, "Expected the handler to not be called, when other events fire");
|
||||
});
|
||||
});
|
||||
|
||||
describe("once", () => {
|
||||
it("fire once when fired recursively", () => {
|
||||
const observable = new Observable();
|
||||
let callCount1 = 0;
|
||||
let callCount2 = 0;
|
||||
const handler2 = function () {
|
||||
callCount2++;
|
||||
}
|
||||
const handler1 = function () {
|
||||
callCount1++;
|
||||
observable.once("test", handler2);
|
||||
observable.notify({ eventName: "test", object: observable });
|
||||
}
|
||||
observable.once("test", handler1);
|
||||
observable.notify({ eventName: "test", object: observable });
|
||||
assert.equal(callCount1, 1, "Expected the first handler to unsubscribe before being fired and to notify just once");
|
||||
assert.equal(callCount2, 1, "Expected the second handler to be fired once when recursively notified by the first handler");
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user