From 92b3d84021f775b7b70d5e4af844687a38930239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20=C5=81aziuk?= Date: Sun, 28 Jan 2018 12:54:13 +0100 Subject: [PATCH] timeout (#21) --- README.md | 14 +++++++++ package.json | 10 +++---- timeout.spec.ts | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ timeout.ts | 26 ++++++++++++++++ 4 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 timeout.spec.ts create mode 100644 timeout.ts diff --git a/README.md b/README.md index da8d78d..8b4648e 100644 --- a/README.md +++ b/README.md @@ -44,12 +44,16 @@ There is already a few libraries with similar functionality, yet this is another ``` typescript import asap from "asap-es"; import delay from "asap-es/delay"; +import timeout from "asap-es/timeout"; +// you can have many independent queues const queue = new asap(); +// promises queue.q(() => Promise.resolve(2)).then(console.log); // console >> 2 +// async functions queue.q(async () => { // do some async things }); @@ -65,4 +69,14 @@ queue.q(() => { throw new Error(); }).catch(console.error); // console >> error + +// timeout a task after given time +queue.q(timeout(200, () => { + // a long task +})); + +// combine delay and timeout +queue.q(delay(10, timeout(5, () => { + // this task waits 10 ms for execution, then timeouts in 5 ms +}))) ``` diff --git a/package.json b/package.json index 85ad6ad..e131f22 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "access": "public", "name": "asap-es", - "version": "1.1.1", + "version": "1.2.0", "description": "asap with promise support", "main": "index", "private": false, @@ -31,11 +31,11 @@ }, "keywords": [ "asap", - "queue", - "task-queue", - "promise", "async", - "asynchronous" + "asynchronous", + "promise", + "queue", + "task-queue" ], "author": "Tomek Łaziuk ", "license": "MIT", diff --git a/timeout.spec.ts b/timeout.spec.ts new file mode 100644 index 0000000..3c79c06 --- /dev/null +++ b/timeout.spec.ts @@ -0,0 +1,80 @@ +import { + expect, +} from "chai"; + +import { + spy, +} from "sinon"; + +import ASAP from "."; +import delay from "./delay"; +import timeout from "./timeout"; + +describe(timeout.name || "timeout", () => { + it("should return a 'function'", () => { + expect(timeout(0, () => void 0)).to.be.a("function"); + }); + it("should the task function be callled", async () => { + const taskSpy = spy(); + const taskNew = timeout(0, taskSpy); + try { + await taskNew(); + } catch { + // pass + } + expect(taskSpy.callCount).to.be.equal(1); + }); + it("should the new task resolve to value of original task", async () => { + const task = () => "abc"; + const taskNew = timeout(0, task); + expect(await taskNew()).to.be.equal("abc"); + }); + it("should the new task reject when execution time exceeds the timeout", (done) => { + const task = () => new Promise( + (resolve, reject) => { + setTimeout(() => { + resolve(); + }, 10); + }, + ); + const taskNew = timeout(0, task); + taskNew().catch(() => done()); + }); + it("should the waiting time for task not count into the task execution time", async () => { + const task = delay(10, (): string => "abc"); + const taskNew = timeout(0, task); + expect(await taskNew()).to.be.equal("abc"); + }); + it("should rejection be instance of 'Error'", async () => { + const task = () => delay(10, "abc"); + const taskNew = timeout(0, task); + let err; + try { + await taskNew(); + } catch (e) { + err = e; + } + expect(err).to.be.instanceOf(Error); + }); + it("should reject if task Promise rejects", (done) => { + const task = () => Promise.reject(new Error()); + const taskNew = timeout(10, task); + taskNew().catch(() => done()); + }); + it("should be working in a queue", async () => { + const queue = new ASAP(); + expect(await queue.q(timeout(10, () => delay(5, "abc")))).to.be.equal("abc"); + }); + it("should reject if task throws", async () => { + const task = () => { throw new Error("error"); }; + const taskNew = timeout(10, task); + let err; + try { + await taskNew(); + } catch (e) { + err = e; + } + expect(err).to.be.instanceOf(Error); + expect((err as Error).message).to.be.equal("error"); + }); +}); diff --git a/timeout.ts b/timeout.ts new file mode 100644 index 0000000..d9fb1c4 --- /dev/null +++ b/timeout.ts @@ -0,0 +1,26 @@ +import { task } from "."; + +/** + * reject when the execution exceeds given time + * + * @param timeout time in milliseconds + * @param fn task to run + */ +export default ( + timeout: number, + fn: task | PromiseLike>, +): (() => Promise) => () => Promise.resolve(fn).then( + // run the logic when task will be ready + (taskFn) => new Promise( + (resolve, reject) => { + Promise.resolve( + // task is ready, yet it may return a promise + taskFn(), + ).then(resolve, reject); + setTimeout(() => { + // reject when the timeout is reached + reject(new Error()); + }, timeout); + }, + ), +);