Skip to content

Commit

Permalink
delay (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
tlaziuk authored Jan 23, 2018
1 parent 500bce9 commit 2efa955
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 22 deletions.
29 changes: 29 additions & 0 deletions delay.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
expect,
} from "chai";

import {
spy,
} from "sinon";

import delay from "./delay";

describe(delay.name || "delay", () => {
it("should return a 'Promise'", () => {
expect(delay(0)).to.be.instanceOf(Promise);
});
it("should be working with negative timeout", async () => {
await delay(-100);
});
it("should resolve value", async () => {
expect(await delay(0, "abc")).to.be.equal("abc");
});
it("should resolve value from 'Promise'", async () => {
expect(await delay(0, Promise.resolve("abc"))).to.be.equal("abc");
});
it("should reject value from 'Promise'", (done) => {
const reject = Promise.reject(new Error());
reject.catch(() => void 0);
delay(0, reject).catch(() => { done(); });
});
});
13 changes: 13 additions & 0 deletions delay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* delay the execution by given amount of time
*
* @param delay time in milliseconds
* @param val optional value to return
*/
export default <T = void>(delay: number, val?: T | PromiseLike<T>) => new Promise<T>(
(resolve) => {
setTimeout(() => {
resolve(val);
}, delay);
},
);
92 changes: 73 additions & 19 deletions index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@ import {

import ASAP, { task } from "./index";

const timeout = <T>(fn: task<T>, time: number = 0) => new Promise<T>((resolve) => {
setTimeout(() => {
resolve(fn());
}, time);
});
import delay from "./delay";

describe(ASAP.name, () => {
it("should be a class", () => {
Expand All @@ -31,10 +27,26 @@ describe(ASAP.name, () => {
expect(asap.c).to.be.equal(1);
});
it("should the queue run", async () => {
const spyFn = spy();
const asap = new ASAP();
const prom = asap.q(spyFn);
expect(prom).to.be.instanceof(Promise);
await prom;
expect(spyFn.callCount).to.be.equal(1);
});
it("should the queue run with a promise of task", async () => {
const spyFn = spy();
const asap = new ASAP();
const prom = asap.q(() => void 0);
const prom = asap.q(Promise.resolve(spyFn));
expect(prom).to.be.instanceof(Promise);
await prom;
expect(spyFn.callCount).to.be.equal(1);
});
it("should reject when promise of a task rejects", (done) => {
const asap = new ASAP();
const prom = asap.q(Promise.reject(new Error()));
expect(prom).to.be.instanceof(Promise);
prom.catch(() => { done(); });
});
it("should handle rejection", async () => {
const asap = new ASAP();
Expand All @@ -47,37 +59,79 @@ describe(ASAP.name, () => {
});
}));
});
it("should the queue run two times", async () => {
it("should the queue run multiple times", async () => {
const asap = new ASAP();
await Promise.all([
asap.q(() => void 0),
asap.q(() => void 0),
asap.q(() => void 0),
asap.q(() => void 0),
]);
}).timeout(10);
it("should the queue run two slow tasks", async () => {
});
it("should the queue run in proper order", async () => {
const asap = new ASAP();
const spyFn1 = spy();
const spyFn2 = spy();
const spyFn3 = spy();
await Promise.all([
asap.q(spyFn1),
asap.q(spyFn2),
asap.q(spyFn3),
]);
expect(spyFn1.calledBefore(spyFn2)).to.be.equal(true);
expect(spyFn2.calledBefore(spyFn3)).to.be.equal(true);
});
it("should the queue run slow tasks", async () => {
const asap = new ASAP();
await Promise.all([
asap.q(() => timeout(() => void 0, 50)),
asap.q(() => timeout(() => void 0, 50)),
asap.q(() => delay(50)),
asap.q(() => delay(50)),
]);
}).timeout(110);
it("should the queue run two slow tasks - concurrency", async () => {
it("should the queue run slow tasks - concurrency", async () => {
const asap = new ASAP();
asap.c = 2;
await Promise.all([
asap.q(() => timeout(() => void 0, 50)),
asap.q(() => timeout(() => void 0, 50)),
asap.q(() => delay(50)),
asap.q(() => delay(50)),
]);
}).timeout(60);
it("should the queue run in proper order - concurrency", async () => {
const asap = new ASAP();
const spyFn1 = spy();
const spyFn2 = spy();
const spyFn3 = spy();
const spyFn4 = spy();
const spyFn5 = spy();
asap.c = 2;
await Promise.all([
asap.q(delay(10, spyFn1)),
asap.q(delay(10, spyFn2)),
asap.q(delay(10, spyFn3)),
asap.q(delay(10, spyFn4)),
asap.q(delay(10, spyFn5)),
]);
expect(spyFn1.callCount).to.be.equal(1, "task 1 not called");
expect(spyFn2.callCount).to.be.equal(1, "task 2 not called");
expect(spyFn3.callCount).to.be.equal(1, "task 3 not called");
expect(spyFn4.callCount).to.be.equal(1, "task 4 not called");
expect(spyFn5.callCount).to.be.equal(1, "task 5 not called");
expect(spyFn1.calledBefore(spyFn3)).to.be.equal(true, "task 1 should run before task 3");
expect(spyFn2.calledBefore(spyFn3)).to.be.equal(true, "task 2 should run before task 3");
expect(spyFn1.calledBefore(spyFn4)).to.be.equal(true, "task 1 should run before task 4");
expect(spyFn2.calledBefore(spyFn4)).to.be.equal(true, "task 2 should run before task 4");
expect(spyFn3.calledBefore(spyFn5)).to.be.equal(true, "task 3 should run before task 5");
expect(spyFn4.calledBefore(spyFn5)).to.be.equal(true, "task 4 should run before task 5");
});
it("should the queue run slow tasks with unmatching concurrency to the tasks number", async () => {
const asap = new ASAP();
asap.c = 2;
await Promise.all([
asap.q(() => timeout(() => void 0, 50)),
asap.q(() => timeout(() => void 0, 50)),
asap.q(() => timeout(() => void 0, 50)),
asap.q(() => timeout(() => void 0, 50)),
asap.q(() => timeout(() => void 0, 50)),
asap.q(() => delay(50)),
asap.q(() => delay(50)),
asap.q(() => delay(50)),
asap.q(() => delay(50)),
asap.q(() => delay(50)),
]);
}).timeout(160);
it("should the queue run when on stress", async () => {
Expand Down
4 changes: 2 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ export default class ASAP {
* }
* ```
*/
public q<T>(fn: task<T>): Promise<T> {
public q<T>(fn: task<T> | PromiseLike<task<T>>): Promise<T> {
return new Promise<T>((resolve, reject) => {
const promFn = () => {
// create a new promise in case when the `fn` throws anything
const prom = new Promise<T>((result) => { result(fn()); });
const prom = Promise.resolve(fn).then((v) => v());

// react on `fn` resolution and set the promise as completed
return prom.then(resolve, reject).then(() => { (this as any)[complete].set(promFn, prom); });
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"access": "public",
"name": "asap-es",
"version": "1.0.3",
"version": "1.1.0",
"description": "asap with promise support",
"main": "index",
"private": false,
Expand Down

0 comments on commit 2efa955

Please sign in to comment.