Skip to content

Rewrite evaluateScript, evaluate, jobQueue and add event loop#352

Open
Jack-Works wants to merge 1 commit into
mainfrom
agent-jobqueue
Open

Rewrite evaluateScript, evaluate, jobQueue and add event loop#352
Jack-Works wants to merge 1 commit into
mainfrom
agent-jobqueue

Conversation

@Jack-Works

Copy link
Copy Markdown
Contributor

Breaking changes

Behavior of realm.evaluateScript or realm.evaluate

If you are using realm.evaluateScript or realm.evaluate, these APIs no longer require calling resumeEvaluate().

realm.evaluateScript and realm.evaluate no longer return a completion.

// old
let completion;
realm.evaluateScript('code', options, (c) => {
  completion = c;
  resolve(c);
});
if (!completion) surroundingAgent.resumeEvaluate({});

// new
realm.evaluateScript('code', options, (completion) => {
  resolve(completion);
});

If you want to preserve the old behavior, where you add an evaluator without running it, do this:

realm.evaluateScript('code', options, (completion) => {
  resolve(completion);
}, false);

If you want to skip the debugger, do this:

realm.evaluateScriptSkipDebugger('code', options);
// or
realm.evaluateScript('code', options, (completion) => {
  resolve(completion);
}, false, { noBreakpoint: true });

Event loop & Job queue

runJobQueue has been removed. Use agent.eventLoop and agent.jobQueue instead. It by default is WebLikeEventLoop and will automatically flush.

JobQueue API

export declare function runSingleJobInQueue(job: Job, onError: (error: Value) => void, finished: () => void): void;
export interface JobQueue extends Markable {
    enqueueFinalizationRegistryCleanupJob(job: Job): void;
    enqueuePromiseJob(job: Job): void;
    enqueueTimeoutJob(job: Job): void;
    enqueueGenericJob(job: Job): void;
    onNewJob: Set<(job: Job) => void>;
    shift(): Job | undefined;
    shiftFinalizationRegistryCleanupJob?(): Job | undefined;
    shiftPromiseJob?(): Job | undefined;
    shiftTimeoutJob?(): Job | undefined;
    shiftGenericJob?(): Job | undefined;
    get length(): number;
}
export declare class BasicJobQueue extends Set<Job> implements JobQueue, Markable {}
export declare class ByTypeJobQueue implements JobQueue, Markable {}

EventLoop API

/** https://nodejs.org/learn/asynchronous-work/event-loop-timers-and-nexttick */
export type NodeJSJobType = 'timers' | 'pending callbacks' | 'idle' | 'prepare' | 'poll' | 'check' | 'close callbacks';
export type EventLoopRunType = 'manual' | 'automatic';
export interface EventLoop extends Markable {
    /**
     * Enqueue a host job (macrotask) now.
     */
    enqueue(type: NodeJSJobType | string, job: Job): void;
    /**
     * Enqueue a host job (macrotask) in the future.
     * It will keep `hasPendingJobs` to be `true` until `enqueue` is called.
     */
    enqueueAsync(type: NodeJSJobType | string, job: Job, executor: (enqueue: () => void, cancel: () => void) => void): void;
    /** Change the automatic run type of the event loop and run it */
    run(type: EventLoopRunType): void;
    runOnce(): void;
    readonly hasPendingJobs: boolean;
    /**
     * Register a callback to be called when there are no async queued jobs.
     *
     * This can be used to implement a mechanism to exit the program when all code has finished executing.
     */
    onNoPendingJob: Set<() => void>;
}

export declare abstract class AbstractEventLoop implements EventLoop {}

export declare class MicroTaskEventLoop extends AbstractEventLoop {}

/** https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide/In_depth */
export declare class WebLikeEventLoop extends AbstractEventLoop {}

/** https://nodejs.org/learn/asynchronous-work/event-loop-timers-and-nexttick */
export declare class NodeJSLikeEventLoop extends AbstractEventLoop {
    fallbackType: NodeJSJobType;
}

Examples: timer

const job: Job = {
  queueName: 'timer',
  callerRealm: surroundingAgent.currentRealmRecord,
  callerScriptOrModule: GetActiveScriptOrModule(),
  job: function* setTimeoutResolve() {
    return yield* Call(callback, Value.undefined, []);
  },
};
// enqueueAsync prevents the event loop from exiting.
surroundingAgent.eventLoop.enqueueAsync('timers', job, (enqueue) => {
  // enqueue() actually enqueues the job.
  setTimeout(enqueue, ms.value);
});

Removal of realm.active and realm.scope()

realm.active has been removed. It did not represent anything useful.

realm.scope() has been removed. Use realm.pushTopContext() instead.

// old
realm.scope(() => {
  doSomething();
});

// new
const pop = realm.pushTopContext();
doSomething();
pop?.();
// in case of manually push and pop the context,
// you may need to run event loop manually.
agent.eventLoop.runOnce();

evalQ

In evalQ((Q, X) => {}), the X parameter is no longer provided. Use unwrapCompletion() or X() instead.

Renames

  1. ExecutionContext.codeEvaluationState has been renamed to ExecutionContext.CodeEvaluationState to match ECMA-262 naming.

  2. Agent.scheduledForCleanup has been renamed to Agent.finalizationRegistryScheduledForCleanup.

  3. The Agent.hostDefined.cleanupFinalizationRegistry hook has moved to Agent.hostDefinedOptions.hostHooks.HostEnqueueFinalizationRegistryCleanupJob.

  4. The type of PrivateEnvironment has changed from PrivateEnvironmentRecord | NullValue to PrivateEnvironmentRecord.

Additions

  1. Add runningExecutionContext() for the running execution context term. surroundingAgent.runningExecutionContext is still supported.
  2. Add currentRealmRecord() for the current realm record term. surroundingAgent.currentRealmRecord is still supported.
  3. Add activeFunctionObject() for the active function object term. surroundingAgent.activeFunctionObject is still supported.
  4. Add intrinsics()['%...%'] for intrinsics. surroundingAgent.intrinsic('%...%') is still supported, but discouraged.
  5. ModuleCache.hasUnfinishedRequests() and ModuleCache.untilAllRequestFinished() have been removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant