Skip to content

Commit

Permalink
+ startOnly method
Browse files Browse the repository at this point in the history
+ `restartOnly` method
= the instance is no longer returned from `start`/`stop` methods, it was useless and possibly confusing
  • Loading branch information
dzek69 committed May 7, 2023
1 parent 35519dd commit c217214
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 15 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [UNRELEASED]
(nothing yet)

## [4.0.2+]
## [5.0.0] - 2023-05-07
### Added
- `startOnly` method
- `restartOnly` method
### Dev
- got rid of default exports in internal files, if you (incorrectly) required internal files previously change your `require`/`import` statements
### Changed
- tutorial/readme update
- the instance is no longer returned from `start`/`stop` methods, it was useless and possibly confusing

## [4.0.2] - 2023-04-25
### Dev
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "oop-timers",
"version": "4.0.2+",
"version": "5.0.0",
"repository": "[email protected]:dzek69/oop-timers.git",
"author": "Jacek Nowacki",
"license": "MIT",
Expand Down
75 changes: 74 additions & 1 deletion src/Interval.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe("Interval", () => {
interval.started.must.be.false();
});

it("doesn't start the interval by defualt", async () => {
it("doesn't start the interval by default", async () => {
const callback = spy();
const interval = new Interval(callback, 100);
interval.started.must.be.false();
Expand Down Expand Up @@ -346,4 +346,77 @@ describe("Interval", () => {

interval.stop();
});

it("allows to start the timer only if not started", async () => {
{
const callback = spy();
const interval = new Interval(callback, 100);
const r1 = interval.startOnly();
await wait(50);
// will not restart
const r2 = interval.startOnly();
await wait(50);
// will not restart - interval is running until it is stopped!
const r3 = interval.startOnly();
await wait(50);
const r4 = interval.startOnly();
await wait(200);
callback.__spy.calls.length.must.be.equal(3); // 3 calls because wait(200) is 2 intervals

r1.must.be.true();
r2.must.be.false();
r3.must.be.false();
r4.must.be.false();

interval.stop();
}

{
const callback = spy();
const interval = new Interval(callback, 100);
// it will keep restarting, so it will call the callback only once
interval.start();
await wait(50);
interval.start();
await wait(50);
interval.start();
await wait(50);
interval.start();
await wait(200);
callback.__spy.calls.length.must.be.equal(1);

interval.stop();
}
});

it("allows to restart the timer only if alredy started", async () => {
const callback = spy();
const interval = new Interval(callback, 100);
const r1 = interval.restartOnly();
r1.must.be.false();

await wait(200);
callback.__spy.calls.length.must.be.equal(0);

interval.start();
const r2 = interval.restartOnly();
await wait(50);
const r3 = interval.restartOnly();
await wait(50);
const r4 = interval.restartOnly();
await wait(50);
const r5 = interval.restartOnly();
await wait(50);
const r6 = interval.restartOnly();
await wait(200);

r2.must.be.true();
r3.must.be.true();
r4.must.be.true();
r5.must.be.true();
r6.must.be.true();

callback.__spy.calls.length.must.equal(1);
interval.stop();
});
});
35 changes: 31 additions & 4 deletions src/Interval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,41 @@ class Interval {
this._instantFirstRun = instantFirstRun;
}
this.stop();
this._start();
}

private _start() {
if (this._time !== Infinity) {
this._timerId = setInterval(this._cb, this._time);
}
if (this._instantFirstRun) {
this._cb();
}
return this;
}

/**
* Starts the interval only if it's not already started
* @returns {boolean} - true if newly started, false if already started
*/
public startOnly() {
if (this._timerId !== null) {
return false;
}
this._start();
return true;
}

/**
* Restarts the interval only if it's already started
* @returns {boolean} - true if restarted, false if not started
*/
public restartOnly() {
if (this._timerId === null) {
return false;
}
this.stop();
this._start();
return true;
}

/**
Expand All @@ -60,15 +88,14 @@ class Interval {
* @returns {Interval} current instance
*/
public stop() {
if (this._timerId) {
if (this._timerId !== null) {
clearInterval(this._timerId);
this._timerId = null;
}
return this;
}

public get started() {
return this._timerId != null;
return this._timerId !== null;
}
}

Expand Down
70 changes: 69 additions & 1 deletion src/Timeout.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe("Timeout", () => {
timer.started.must.be.false();
});

it("doesn't fire the callback by defualt", async () => {
it("doesn't fire the callback by default", async () => {
const callback = spy();
const timer = new Timeout(callback, 250);

Expand Down Expand Up @@ -226,4 +226,72 @@ describe("Timeout", () => {
timeout.stop();
timeout2.stop();
});

it("allows to start the timer only if not started", async () => {
{
const callback = spy();
const timeout = new Timeout(callback, 100);
const r1 = timeout.startOnly();
await wait(50);
// will not restart
const r2 = timeout.startOnly();
await wait(50);
// should start again
const r3 = timeout.startOnly();
await wait(50);
const r4 = timeout.startOnly();
await wait(200);
callback.__spy.calls.length.must.be.gt(1);

r1.must.be.true();
r2.must.be.false();
r3.must.be.true();
r4.must.be.false();
}

{
const callback = spy();
const timeout = new Timeout(callback, 100);
// it will keep restarting, so it will call the callback only once
timeout.start();
await wait(50);
timeout.start();
await wait(50);
timeout.start();
await wait(50);
timeout.start();
await wait(200);
callback.__spy.calls.length.must.be.equal(1);
}
});

it("allows to restart the timer only if alredy started", async () => {
const callback = spy();
const timeout = new Timeout(callback, 100);
const r1 = timeout.restartOnly();
r1.must.be.false();

await wait(200);
callback.__spy.calls.length.must.be.equal(0);

timeout.start();
const r2 = timeout.restartOnly();
await wait(50);
const r3 = timeout.restartOnly();
await wait(50);
const r4 = timeout.restartOnly();
await wait(50);
const r5 = timeout.restartOnly();
await wait(50);
const r6 = timeout.restartOnly();
await wait(200);

r2.must.be.true();
r3.must.be.true();
r4.must.be.true();
r5.must.be.true();
r6.must.be.true();

callback.__spy.calls.length.must.equal(1);
});
});
38 changes: 31 additions & 7 deletions src/Timeout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,38 +29,62 @@ class Timeout {
* Starts or restarts the timer
*
* @param {number} [newTime] - override time to call the callback
* @returns {Timeout} current instance
*/
public start(newTime?: number) {
if (newTime != null) {
validateTime(newTime);
this._time = newTime;
}
this.stop();
this._start();
}

private _start() {
if (this._time !== Infinity) {
this._timerId = setTimeout(() => {
this._cb();
this.stop();
}, this._time);
}
return this;
}

/**
* Starts the timer only if it's not already started
* @returns {boolean} - true if newly started, false if already started
*/
public startOnly() {
if (this._timerId !== null) {
return false;
}
this._start();
return true;
}

/**
* Restarts the timer only if it's already started
* @returns {boolean} - true if restarted, false if not started
*/
public restartOnly() {
if (this._timerId === null) {
return false;
}
this.stop();
this._start();
return true;
}

/**
* Stops the timer, so callback won't be fired
*
* @returns {Timeout} current instance
*/
public stop() {
if (this._timerId) {
if (this._timerId !== null) {
clearTimeout(this._timerId);
this._timerId = null;
}
return this;
}

public get started() {
return this._timerId != null;
return this._timerId !== null;
}
}

Expand Down
2 changes: 2 additions & 0 deletions tutorials/Usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ timeout.start();
button.addEventListener('click', () => timeout.start(2000));
```

> Important: `startOnly` and `restartOnly` does not support changing timeout value.
## Important difference from setTimeout and setInterval

A `timer.start()` method has to be run in order to start the timeout/interval, as opposed to using native
Expand Down

0 comments on commit c217214

Please sign in to comment.