Promise Extensions for JavaScript (prex)
Asynchronous coordination for JavaScript and TypeScript.
DEPRECATED: This package has been deprecated in favor of the following packages that replace it:]
@esfx/cancelable
:
CancelError
@esfx/canceltoken
:
is nowCancellationToken
CancelToken
is nowCancellationTokenSource
CancelSource
/CancelToken.source()
@esfx/async-manualresetevent
:
is nowManualResetEvent
AsyncManualResetEvent
@esfx/async-autoresetevent
:
is nowAutoResetEvent
AsyncAutoResetEvent
@esfx/async-semaphore
:
is nowSemaphore
AsyncSemaphore
@esfx/async-countdown
:
is nowCountdownEvent
AsyncCountdownEvent
@esfx/async-barrier
:
is nowBarrier
AsyncBarrier
@esfx/async-readerwriterlock
:
is nowReaderWriterLock
AsyncReaderWriterLock
@esfx/async-deferred
:
Deferred
@esfx/async-queue
:
AsyncQueue
@esfx/async-stack
:
AsyncStack
@esfx/async-delay
:
delay(msec, value?)
- NOTE: There are no replacements for
AsyncBoundedQueue
orPulsar
, they have been deprecated.
This library contains a number of coordination primitives to assist in asynchronous application development in JavaScript and TypeScript. This includes useful additions for building complex asynchronous logic including:
- Cancellation [Sample, API Reference]
- Coordination [Sample, API Reference]
- Scheduling [Sample, API Reference]
Installing
For the latest version:
npm install prex
Documentation
Samples
Cancellation
API Reference: Cancellation
The CancellationTokenSource and CancellationToken primitives allow you to create asynchronous operations that can be canceled externally. The following is an example of a function used to download a file asynchronously that can be canceled:
import * as http from "http";
import * as fs from "fs";
import { CancellationTokenSource, CancellationToken } from "prex";
function downloadFile(from: string, to: string, token = CancellationToken.none) {
return new Promise<void>((resolve, reject) => {
const request = http.get(from);
// abort the request if canceled.
const registration = token.register(() => {
request.abort();
reject(new Error("Operation canceled."));
});
request.on("error", err => {
registration.unregister();
reject(err);
});
request.on("response", (response: http.IncomingMessage) => {
response
.pipe(fs.createWriteStream(to))
.on("error", err => {
registration.unregister();
reject(err);
})
.on("end", () => {
registration.unregister();
resolve();
});
});
});
}
async function main() {
const source = new CancellationTokenSource();
// cancel the source if the file takes more than one second to download
setTimeout(() => source.cancel(), 1000);
await downloadFile("http://tempuri.org/some/file", "file", source.token);
}
Coordination
API Reference: Coordination
A Semaphore can be used to protect access to a critical section of your code when you must limit access across multiple async operations. The following is an example of two functions which both need exclusive access to a single resource but could possibly be preempted when suspended while awaiting an asynchronous operation:
import { Semaphore } from "prex";
const criticalResource = new Semaphore(1);
async function updateCriticalLocalResource() {
// Acquire a lock on the critical resource
await criticalResource.wait();
// Make local changes...
// await a network resources
await postUpdateToNetworkResource(changes);
// release the lock
criticalResource.release();
}
async function deleteCriticalLocalResource() {
// Acquire a lock on the critical resource
await criticalResource.wait();
// Make local changes...
// await a network resources
await postUpdateToNetworkResource(changes);
// release the lock
criticalResource.release();
}
declare function postUpdateToNetworkResource(changes): Promise<void>;
A Barrier can be used to coordinate complex async operations:
import { Barrier } from "prex";
const barrier = new Barrier(/*participantCount*/ 3);
async function processNpcAI() {
while (true) {
// process AI activities...
await barrier.signalAndWait();
}
}
async function processGameRules() {
while (true) {
// process game rules
await barrier.signalAndWait();
}
}
async function processGameInput() {
while (true) {
// process user input
await barrier.signalAndWait();
}
}
Scheduling
API Reference: Scheduling
An AsyncQueue is a useful primitive for scheduling asynchronous work:
import { AsyncQueue } from "prex";
const workItems = new AsyncQueue();
function queueUserWorkItem(action: () => void) {
workItems.put(action);
}
async function processWorkItems() {
while (true) {
const action = await workItems.get();
try {
action();
}
catch (e) {
console.error(e);
}
}
}
License
Copyright (c) Microsoft Corporation. Licensed under the Apache License, Version 2.0.
See LICENSE file in the project root for details.