API to intercept Promises in V8

55 views
Skip to first unread message

Darin Dimitrov

unread,
Feb 11, 2020, 2:42:50 PM2/11/20
to v8-users
I am embedding V8 in my C++ application and I have registered a custom "test" function on the global object taking a callback as parameter:

test(function() {
    console.log("callback");      
});

The "test" function starts a new thread and executes the callback on this thread.

Now I can wrap this function in a Promise:

new Promise(function(resolve, reject) {
    test(resolve);
}).then(function() {
    console.log("this callback is executed on the background thread created by the 'test' function");
});

I am looking for a way to somehow hook into V8 promises so that they are always resolved on the main thread of my application.

I thought that using a custom platform might help but couldn't find any useful method that I can override. It does provide the "CallOnWorkerThread" method but can I relate this to promises? Does V8 provide some API to intercept and replace the promise implementation?

Ben Noordhuis

unread,
Feb 11, 2020, 3:31:18 PM2/11/20
to v8-users
Some additional info is needed because it's not wholly clear to me how
you envision this would work. How exactly is your program using
threads?

A V8 isolate is not reentrant. You can migrate it between threads but
only one thread can enter it (and should hold a v8::Locker to ensure
that it's the only one.)

You have some control over when microtasks (promises) are executed
with isolate->SetMicrotasksPolicy(MicrotasksPolicy::kExplicit) and
isolate->RunMicrotasks().

Darin Dimitrov

unread,
Feb 11, 2020, 3:59:40 PM2/11/20
to v8-users
Hi Ben,

Thanks for the reply. My program is actually a MacOS application and it uses its SDK to create threads. I am using v8::Locker to ensure that only one thread is accessing the isolate. And this works quite well. I can also use the MacOS SDK to schedule some work on any thread. The problem I am having is how to hook into V8 promises so that I can control over which thread the resolve callback i executed.

For example JavaScriptCore has the possibility to specify a callback when initializing the global object which allows to control and customize how are the promise callbacks executed: https://github.com/WebKit/webkit/blob/master/Source/JavaScriptCore/runtime/JSGlobalObject.cpp#L341

I am looking for a similar API in V8 if it exists.

On Tuesday, February 11, 2020 at 10:31:18 PM UTC+2, Ben Noordhuis wrote:

Darin Dimitrov

unread,
Feb 12, 2020, 8:31:26 AM2/12/20
to v8-users
I managed to get this working by replacing the native Promise object by executing the following script:

    global.Promise = new Proxy(global.Promise, {
        construct: function(target, args) {
            const origFunc = args[0];
            return new target(function(resolve, reject) {
                origFunc(
                    value => executeOnMainThread(resolve.bind(this, value)),
                    reason => executeOnMainThread(reject.bind(this, reason))
                );
            });
        }
    });

In this example, I have registered the "executeOnMainThread" function on the global object which will call the specified js function argument on the main thread.

Of course if this can be achieved without replacing the global Promise object, that would be even better.

Ben Noordhuis

unread,
Feb 13, 2020, 3:31:27 AM2/13/20
to v8-users
On Wed, Feb 12, 2020 at 2:31 PM Darin Dimitrov <darin.d...@gmail.com> wrote:
>
> I managed to get this working by replacing the native Promise object by executing the following script:
>
> global.Promise = new Proxy(global.Promise, {
> construct: function(target, args) {
> const origFunc = args[0];
> return new target(function(resolve, reject) {
> origFunc(
> value => executeOnMainThread(resolve.bind(this, value)),
> reason => executeOnMainThread(reject.bind(this, reason))
> );
> });
> }
> });
>
> In this example, I have registered the "executeOnMainThread" function on the global object which will call the specified js function argument on the main thread.
>
> Of course if this can be achieved without replacing the global Promise object, that would be even better.

I don't think V8 lets you do that right now. There's
isolate->SetPromiseHook() but that's intended more for tracing/logging
than for intercepting.
Reply all
Reply to author
Forward
0 new messages