Skip to content

Commit

Permalink
Add util/async.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
ry committed May 16, 2019
1 parent 98257ef commit cfc8108
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 0 deletions.
57 changes: 57 additions & 0 deletions util/async.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.

// TODO(ry) It'd be better to make Deferred a class that inherits from
// Promise, rather than an interface. This is possible in ES2016, however
// typescript produces broken code when targeting ES5 code.
// See https://github.com/Microsoft/TypeScript/issues/15202
// At the time of writing, the github issue is closed but the problem remains.
export interface Deferred<T> extends Promise<T> {
resolve: (value?: T | PromiseLike<T>) => void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
reject: (reason?: any) => void;
}

/** Creates a Promise with the `reject` and `resolve` functions
* placed as methods on the promise object itself. It allows you to do:
*
* const p = deferred<number>();
* // ...
* p.resolve(42);
*/
export function deferred<T>(): Deferred<T> {
let methods;
const promise = new Promise<T>(
(resolve, reject): void => {
methods = { resolve, reject };
}
);
return Object.assign(promise, methods) as Deferred<T>;
}

export class AsyncQueue<T> {
private items: T[] = [];
private waiting: Array<Deferred<T>> = [];

get length(): number {
return this.items.length;
}

push(x: T): void {
if (this.waiting.length > 0) {
const p = this.waiting.shift();
p.resolve(x);
} else {
this.items.push(x);
}
}

async shift(): Promise<T> {
if (this.items.length > 0) {
return this.items.shift();
} else {
const d = deferred<T>();
this.waiting.push(d);
return d;
}
}
}
25 changes: 25 additions & 0 deletions util/async_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { test, runIfMain } from "../testing/mod.ts";
import { assertEquals } from "../testing/asserts.ts";
import { AsyncQueue, deferred } from "./async.ts";

test(async function asyncDeferred(): Promise<void> {
const d = deferred<number>();
d.resolve(12);
});

test(async function asyncQueue(): Promise<void> {
const q = new AsyncQueue<number>();
q.push(1);
q.push(2);
assertEquals(2, q.length);
assertEquals(1, await q.shift());
assertEquals(2, await q.shift());
setTimeout((): void => {
q.push(3);
}, 1);
assertEquals(0, q.length);
assertEquals(3, await q.shift());
});

runIfMain(import.meta);
1 change: 1 addition & 0 deletions util/test.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
import "./async_test.ts";
import "./deep_assign_test.ts";

0 comments on commit cfc8108

Please sign in to comment.