6.031TS
6.031TS — Software Construction
TypeScript Pilot — Spring 2021

Code Examples for Reading 21

Download

You can also download a ZIP file containing this code.

Seems to be necessary to have a triple-backtick block at the start of this page,
otherwise all the pre/code tags below aren't syntax highlighted.
So create a hidden one.

timeout.ts

import assert from 'assert';
import Q from 'q';

/**
 * @param milliseconds duration to wait
 * @returns a promise that fulfills no less than `milliseconds` after timeout() was called
 */
async function timeout(milliseconds:number):Promise<void> {}
// implemented three ways below:

// version 1:
// using a Q.Deferred object, 
//  which consists of a promise and its resolve and reject operations:
async function timeout1(milliseconds:number):Promise<void> {
    const deferred: Q.Deferred<void> = Q.defer();
    setTimeout(function() {
        deferred.resolve(); // this mutates deferred.promise into the fulfilled state
        // or we could call deferred.reject(new Error(...)) to reject the promise instead
    }, milliseconds);
    return deferred.promise;
}

// version 2:
// implemented using Promise constructor,
// explicitly pulling out its resolve and reject operations:
async function timeout2(milliseconds:number):Promise<void> {
    let resolvePromise;
    let rejectPromise;
    const promise = new Promise<void>(function(resolve, reject) {
        resolvePromise = resolve;
        rejectPromise = reject;
    });
    assert(resolvePromise);
    setTimeout(resolvePromise, milliseconds);
    return promise;
}

// version 3:
// implemented using Promise constructor, more concisely
async function timeout3(milliseconds:number):Promise<void> {
    return new Promise<void>(function(resolve, reject) {
        setTimeout(resolve, milliseconds);
    })
}

TinyQueue.ts

import assert from 'assert';
import { describe, it } from 'mocha';
import Q from 'q';

/**
 * Asynchronous queue of size 1.
 */
export class TinyQueue<E> {

    private element: E|undefined = undefined;

    private waitingToPut: Array<Q.Deferred<void>> = [];
    private waitingToTake: Array<Q.Deferred<void>> = [];

    // RI:
    //    if any puts are waiting (waitingToPut.length > 0), then queue is full (element !== undefined)
    //    if any takes are waiting (waitingToTake.length > 0), then queue is empty (element === undefined)

    /**
     * Put an element onto this queue.
     * @param elt  element to put on queue
     * @returns promise that fulfills once the element gets onto the queue
     */
    public async put(elt:E):Promise<void> {
        console.log('put:', elt);

        if (this.element !== undefined) {
            // wait until the queue is empty
            const deferred: Q.Deferred<void> = Q.defer();
            this.waitingToPut.push(deferred);
            await deferred.promise;
        }
        assert(this.element === undefined);
        
        this.element = elt;

        // notify first take() call that is waiting, if any
        const deferred = this.waitingToTake.shift();
        if (deferred) {
            deferred.resolve();
        }
    }

    /**
     * Remove and return element from this queue.
     * @returns element taken from queue
     */
    public async take():Promise<E> {
        console.log('take');

        if (this.element === undefined) {
            // wait until the queue has an element
            const deferred: Q.Deferred<void> = Q.defer();
            this.waitingToTake.push(deferred);
            await deferred.promise;
        }

        const elt = this.element;
        assert(elt !== undefined);
        this.element = undefined;

        // notify first put() call that is waiting, if any
        const deferred = this.waitingToPut.shift();
        if (deferred) {
            deferred.resolve();
        }

        return elt;
    }

}