Socket
Socket
Sign inDemoInstall

@open-draft/deferred-promise

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@open-draft/deferred-promise - npm Package Compare versions

Comparing version 2.0.0 to 2.1.0

build/DeferredPromise.standalone.d.ts

15

build/createDeferredExecutor.d.ts
export declare type PromiseState = 'pending' | 'fulfilled' | 'rejected';
export declare type ResolveFunction<Data extends any, Result = void> = (value: Data) => Result | PromiseLike<Result>;
export declare type RejectFunction<Result = unknown> = (reason?: unknown) => Result | PromiseLike<Result>;
export declare type DeferredPromiseExecutor<Input = void, Output = Input> = {
(resolve?: ResolveFunction<any, unknown>, reject?: RejectFunction): void;
resolve: ResolveFunction<Input, Output | void>;
reject: RejectFunction;
result?: Output | Input;
export declare type Executor<Value> = ConstructorParameters<typeof Promise<Value>>[0];
export declare type ResolveFunction<Value> = Parameters<Executor<Value>>[0];
export declare type RejectFunction<Reason> = Parameters<Executor<Reason>>[1];
export declare type DeferredPromiseExecutor<Input = never, Output = Input> = {
(resolve?: ResolveFunction<Input>, reject?: RejectFunction<any>): void;
resolve: ResolveFunction<Input>;
reject: RejectFunction<any>;
result?: Output;
state: PromiseState;

@@ -10,0 +11,0 @@ rejectionReason?: unknown;

@@ -8,18 +8,20 @@ "use strict";

executor.resolve = (data) => {
queueMicrotask(() => {
if (executor.state === 'pending') {
executor.state = 'fulfilled';
executor.result = data;
resolve(data);
}
});
if (executor.state !== 'pending') {
return;
}
executor.result = data;
const onFulfilled = (value) => {
executor.state = 'fulfilled';
return value;
};
return resolve(data instanceof Promise ? data : Promise.resolve(data).then(onFulfilled));
};
executor.reject = (reason) => {
if (executor.state !== 'pending') {
return;
}
queueMicrotask(() => {
if (executor.state === 'pending') {
executor.state = 'rejected';
executor.rejectionReason = reason;
reject(reason);
}
executor.state = 'rejected';
});
return reject((executor.rejectionReason = reason));
};

@@ -26,0 +28,0 @@ });

@@ -1,23 +0,12 @@

import { PromiseState, ResolveFunction, RejectFunction } from './createDeferredExecutor';
/**
* @example
* function getPort() {
* const portReadyPromise = new DeferredPromise<number>()
* port.on('ready', (port) => portReadyPromise.resolve(port))
* port.on('error', (error) => portReadyPromise.reject(error))
* returtn portReadyPromise
* }
*/
export declare class DeferredPromise<Input = never, Output = Input> {
import { type Executor, type RejectFunction, type ResolveFunction } from './createDeferredExecutor';
export declare class DeferredPromise<Input, Output = Input> extends Promise<Input> {
#private;
resolve: (value: Input) => void;
reject: (reason?: unknown) => void;
constructor();
static get [Symbol.species](): PromiseConstructor;
get [Symbol.toStringTag](): string;
get state(): PromiseState;
resolve: ResolveFunction<Output>;
reject: RejectFunction<Output>;
constructor(executor?: Executor<Input> | null);
get state(): import("./createDeferredExecutor").PromiseState;
get rejectionReason(): unknown;
then<FulfillmentResult = Output, RejectionResult = never>(onFulfilled?: ResolveFunction<Output, FulfillmentResult> | null, onRejected?: RejectFunction<RejectionResult> | null): DeferredPromise<Input, FulfillmentResult | RejectionResult>;
catch<Result>(onRejected?: RejectFunction<Result>): DeferredPromise<Input, Output | Result>;
finally(onSettled?: (() => void) | null): DeferredPromise<Input, Output>;
then<ThenResult = Input, CatchResult = never>(onFulfilled?: (value: Input) => ThenResult | PromiseLike<ThenResult>, onRejected?: (reason: any) => CatchResult | PromiseLike<CatchResult>): DeferredPromise<ThenResult | CatchResult, Output>;
catch<CatchResult = never>(onRejected?: (reason: any) => CatchResult | PromiseLike<CatchResult>): DeferredPromise<Input | CatchResult, Output>;
finally(onfinally?: () => void | Promise<any>): DeferredPromise<Input, Output>;
}

@@ -5,28 +5,16 @@ "use strict";

const createDeferredExecutor_1 = require("./createDeferredExecutor");
/**
* @example
* function getPort() {
* const portReadyPromise = new DeferredPromise<number>()
* port.on('ready', (port) => portReadyPromise.resolve(port))
* port.on('error', (error) => portReadyPromise.reject(error))
* returtn portReadyPromise
* }
*/
class DeferredPromise {
#promise;
class DeferredPromise extends Promise {
#executor;
resolve;
reject;
constructor() {
this.#executor = (0, createDeferredExecutor_1.createDeferredExecutor)();
this.#promise = new Promise(this.#executor);
constructor(executor = null) {
const deferredExecutor = (0, createDeferredExecutor_1.createDeferredExecutor)();
super((originalResolve, originalReject) => {
deferredExecutor(originalResolve, originalReject);
executor?.(deferredExecutor.resolve, deferredExecutor.reject);
});
this.#executor = deferredExecutor;
this.resolve = this.#executor.resolve;
this.reject = this.#executor.reject;
}
static get [Symbol.species]() {
return Promise;
}
get [Symbol.toStringTag]() {
return 'DeferredPromise';
}
get state() {

@@ -39,89 +27,14 @@ return this.#executor.state;

then(onFulfilled, onRejected) {
const derivedPromise = new DeferredPromise();
const resolveDerivedPromise = (result) => {
if (typeof onFulfilled === 'function') {
try {
const nextResult = onFulfilled(result);
derivedPromise.#executor.resolve(nextResult);
}
catch (error) {
rejectDerivedPromise(error);
}
return;
}
/**
* @note Use the executor directly because the "resolve" method
* always gets overridden to point to the previous Promise in the chain.
*/
derivedPromise.#executor.resolve(result);
};
const rejectDerivedPromise = (result) => {
if (typeof onRejected === 'function') {
try {
const nextReason = onRejected(result);
/**
* @note If the rejection has a handler callback ("catch"),
* resolve the chained promise instead of rejecting it.
* The "catch" callback is there precisely to prevent
* uncaught promise rejection errors.
*/
derivedPromise.#executor.resolve(nextReason);
/**
* @note Since the handled rejected promise was resolved internally,
* still mark its state as rejected. Do so in the next microtask
* because executor rejects the promise in the next task as well
*/
queueMicrotask(() => {
derivedPromise.#executor.state = 'rejected';
derivedPromise.#executor.rejectionReason = nextReason;
});
}
catch (error) {
rejectDerivedPromise(error);
}
return;
}
derivedPromise.#executor.reject(result);
};
switch (this.state) {
case 'pending': {
/**
* @note Override the chainable "resolve" so that when called
* it executes the resolve of the Promise from which it was
* chained from.
*
* @example
* const p1 = new DeferredPromise().then(A).then(B)
* p1.resolve()
*
* Here, "p1" points to the rightmost promise (B) but the
* order of resolving the value must be left-to-right:
* Initial -> A -> B
*/
derivedPromise.resolve = this.resolve;
derivedPromise.reject = this.reject;
this.#promise.then(resolveDerivedPromise, rejectDerivedPromise);
break;
}
case 'fulfilled': {
resolveDerivedPromise(this.#executor.result);
break;
}
case 'rejected': {
rejectDerivedPromise(this.#executor.rejectionReason);
break;
}
}
return derivedPromise;
return this.#decorate(super.then(onFulfilled, onRejected));
}
catch(onRejected) {
return this.then(undefined, onRejected);
return this.#decorate(super.catch(onRejected));
}
finally(onSettled) {
return this.then((result) => {
onSettled?.();
return result;
}, (reason) => {
onSettled?.();
throw reason;
finally(onfinally) {
return this.#decorate(super.finally(onfinally));
}
#decorate(promise) {
return Object.defineProperties(promise, {
resolve: { configurable: true, value: this.resolve },
reject: { configurable: true, value: this.reject },
});

@@ -128,0 +41,0 @@ }

{
"name": "@open-draft/deferred-promise",
"version": "2.0.0",
"description": "A Promise that can be resolved/rejected elsewhere",
"version": "2.1.0",
"description": "A Promise-compatible abstraction that defers resolving/rejecting promises to another closure.",
"main": "./build/index.js",

@@ -9,2 +9,3 @@ "typings": "./build/index.d.ts",

"test": "jest",
"test:compliance": "export NODE_OPTIONS=--loader=tsx || set NODE_OPTIONS=--loader=tsx&& npx -y promises-aplus-tests ./test/aplus-tests-adapter.ts",
"prebuild": "rimraf ./build",

@@ -22,3 +23,4 @@ "build": "tsc",

"resolve",
"reject"
"reject",
"executor"
],

@@ -33,4 +35,5 @@ "author": "Artem Zakharchenko",

"ts-jest": "^29.0.0",
"tsx": "^3.12.1",
"typescript": "^4.8.3"
}
}

@@ -186,1 +186,7 @@ # Deferred Promise

See [`DeferredExecutor.rejectionReason`](#deferredexecutorrejectionreason)
---
## Mentions
- [Jonas Kuske](https://github.com/jonaskuske) for the phenomenal work around improving Promise-compliance.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc