mirror of
https://github.com/aspnet/JavaScriptServices.git
synced 2025-12-24 02:30:13 +00:00
86 lines
3.1 KiB
TypeScript
86 lines
3.1 KiB
TypeScript
import * as domain from 'domain';
|
|
import * as domainContext from 'domain-context';
|
|
|
|
// Not using symbols, because this may need to run in a version of Node.js that doesn't support them
|
|
const domainTasksStateKey = '__DOMAIN_TASKS';
|
|
const domainTaskBaseUrlStateKey = '__DOMAIN_TASK_INTERNAL_FETCH_BASEURL__DO_NOT_REFERENCE_THIS__';
|
|
|
|
let noDomainBaseUrl: string;
|
|
|
|
export function addTask<T>(task: PromiseLike<T>): PromiseLike<T> {
|
|
if (task && domain.active) {
|
|
const state = domainContext.get(domainTasksStateKey) as DomainTasksState;
|
|
if (state) {
|
|
state.numRemainingTasks++;
|
|
task.then(() => {
|
|
// The application may have other listeners chained to this promise *after*
|
|
// this listener, which may in turn register further tasks. Since we don't
|
|
// want the combined task to complete until all the handlers for child tasks
|
|
// have finished, delay the response to give time for more tasks to be added
|
|
// synchronously.
|
|
setTimeout(() => {
|
|
state.numRemainingTasks--;
|
|
if (state.numRemainingTasks === 0 && !state.hasIssuedSuccessCallback) {
|
|
state.hasIssuedSuccessCallback = true;
|
|
setTimeout(() => {
|
|
state.completionCallback(/* error */ null);
|
|
}, 0);
|
|
}
|
|
}, 0);
|
|
}, (error) => {
|
|
state.completionCallback(error);
|
|
});
|
|
}
|
|
}
|
|
|
|
return task;
|
|
}
|
|
|
|
export function run<T>(codeToRun: () => T, completionCallback: (error: any) => void): T {
|
|
let synchronousResult: T;
|
|
domainContext.runInNewDomain(() => {
|
|
const state: DomainTasksState = {
|
|
numRemainingTasks: 0,
|
|
hasIssuedSuccessCallback: false,
|
|
completionCallback: domain.active.bind(completionCallback)
|
|
};
|
|
|
|
try {
|
|
domainContext.set(domainTasksStateKey, state);
|
|
synchronousResult = codeToRun();
|
|
|
|
// If no tasks were registered synchronously, then we're done already
|
|
if (state.numRemainingTasks === 0 && !state.hasIssuedSuccessCallback) {
|
|
state.hasIssuedSuccessCallback = true;
|
|
setTimeout(() => {
|
|
state.completionCallback(/* error */ null);
|
|
}, 0);
|
|
}
|
|
} catch(ex) {
|
|
state.completionCallback(ex);
|
|
}
|
|
});
|
|
|
|
return synchronousResult;
|
|
}
|
|
|
|
export function baseUrl(url?: string): string {
|
|
if (url) {
|
|
if (domain.active) {
|
|
// There's an active domain (e.g., in Node.js), so associate the base URL with it
|
|
domainContext.set(domainTaskBaseUrlStateKey, url);
|
|
} else {
|
|
// There's no active domain (e.g., in browser), so there's just one shared base URL
|
|
noDomainBaseUrl = url;
|
|
}
|
|
}
|
|
|
|
return domain.active ? domainContext.get(domainTaskBaseUrlStateKey) : noDomainBaseUrl;
|
|
}
|
|
|
|
interface DomainTasksState {
|
|
numRemainingTasks: number;
|
|
hasIssuedSuccessCallback: boolean;
|
|
completionCallback: (error: any) => void;
|
|
}
|