Is there a "weak ScriptPromise"?

44 views
Skip to first unread message

Dominic Cooney

unread,
Jun 10, 2014, 1:52:10 AM6/10/14
to blink-dev, Kentaro Hara, Yutaka Hirano
I think I need a cycles-defeating promise, something like a ScriptPromise with a weak handle and an hidden property from wrapper to promise. Can you give me some implementation pointers?

Here's my situation:

I have an object, navigator.serviceWorker, that vends promises through a "ready" property.

The implementation today is very simple, because it either returns a resolved promise, or never resolves the promise. In both cases it creates a promise and hands it back to the user.

In the next step I need to vend a promise that I will resolve later--possibly never. IIRC the way to do this is to have C++ have a weak reference to the promise, and set up a hidden reference from the wrapper of the source (navigator.serviceWorker) to the sink (the promise) so V8 GC can see and manage that cycle.

ScriptValue and ScriptPromises are such clean abstractions, can I pollute them by teaching them about weak references? Or should I add WeakScriptPromise? Or something else entirely?

TIA,

Dominic

Yutaka Hirano

unread,
Jun 10, 2014, 2:09:57 AM6/10/14
to Dominic Cooney, blink-dev, Kentaro Hara
In the next step I need to vend a promise that I will resolve later--possibly never.
Sorry I 'm not sure what you meant, so let me confirm.
Do you want to return the same promise over multiple calls for "ready"?

Adam Barth

unread,
Jun 10, 2014, 11:09:32 AM6/10/14
to domi...@google.com, blin...@chromium.org, har...@chromium.org, yhi...@chromium.org
On Mon Jun 09 2014 at 10:52:53 PM, 'Dominic Cooney' via blink-dev <blin...@chromium.org> wrote:
I think I need a cycles-defeating promise, something like a ScriptPromise with a weak handle and an hidden property from wrapper to promise. Can you give me some implementation pointers?

Here's my situation:

I have an object, navigator.serviceWorker, that vends promises through a "ready" property.

The implementation today is very simple, because it either returns a resolved promise, or never resolves the promise. In both cases it creates a promise and hands it back to the user.

In the next step I need to vend a promise that I will resolve later--possibly never.

Is there some point at which you know that you'll never resolve the promise?  That's the point at which to break the cycle.  For example, we typically break these cycles when the ActiveDOMObject::stop notification is called.

One difficulty with using weak processing to define the point at which the promise will never resolve is that we'll leak some implementation details about when we trigger garbage collection.

Adam

Dominic Cooney

unread,
Jun 10, 2014, 11:41:00 AM6/10/14
to Yutaka Hirano, Kentaro Hara, blink-dev


On Jun 9, 2014 11:09 PM, "Yutaka Hirano" <yhi...@chromium.org> wrote:
>>
>> In the next step I need to vend a promise that I will resolve later--possibly never.
>
> Sorry I 'm not sure what you meant, so let me confirm.
> Do you want to return the same promise over multiple calls for "ready"?

I don't think the spec requires that, and I was planning on returning multiple different ones. How is the multiplicity important?

Dominic Cooney

unread,
Jun 10, 2014, 11:50:23 AM6/10/14
to Adam Barth, yhi...@chromium.org, har...@chromium.org, blin...@chromium.org


On Jun 10, 2014 8:09 AM, "Adam Barth" <aba...@google.com> wrote:
>
> On Mon Jun 09 2014 at 10:52:53 PM, 'Dominic Cooney' via blink-dev <blin...@chromium.org> wrote:
>>
>> I think I need a cycles-defeating promise, something like a ScriptPromise with a weak handle and an hidden property from wrapper to promise. Can you give me some implementation pointers?
>>
>> Here's my situation:
>>
>> I have an object, navigator.serviceWorker, that vends promises through a "ready" property.
>>
>> The implementation today is very simple, because it either returns a resolved promise, or never resolves the promise. In both cases it creates a promise and hands it back to the user.
>>
>> In the next step I need to vend a promise that I will resolve later--possibly never.
>
>
> Is there some point at which you know that you'll never resolve the promise?  That's the point at which to break the cycle.  For example, we typically break these cycles when the ActiveDOMObject::stop notification is called.

I think it is the frame navigating. So navigator.serviceWorker, which is already a ContextLifecycleObserver, should simply use that as a signal to relinquish the Promise handles?

> One difficulty with using weak processing to define the point at which the promise will never resolve is that we'll leak some implementation details about when we trigger garbage collection.

Leak implementation details to whom?

Anne van Kesteren

unread,
Jun 10, 2014, 11:54:31 AM6/10/14
to Dominic Cooney, Yutaka Hirano, Kentaro Hara, blink-dev
On Tue, Jun 10, 2014 at 5:40 PM, 'Dominic Cooney' via blink-dev
<blin...@chromium.org> wrote:
> On Jun 9, 2014 11:09 PM, "Yutaka Hirano" <yhi...@chromium.org> wrote:
>> Do you want to return the same promise over multiple calls for "ready"?
>
> I don't think the spec requires that, and I was planning on returning
> multiple different ones. How is the multiplicity important?

It should return the same promise. A property that returns a new
object each time you get it without the environment having changed is
not good. You want to preserve obj.x === obj.x.


--
http://annevankesteren.nl/

Adam Barth

unread,
Jun 10, 2014, 11:57:34 AM6/10/14
to domi...@google.com, yhi...@chromium.org, har...@chromium.org, blin...@chromium.org
On Tue Jun 10 2014 at 8:50:19 AM, Dominic Cooney <domi...@google.com> wrote:

On Jun 10, 2014 8:09 AM, "Adam Barth" <aba...@google.com> wrote:
> On Mon Jun 09 2014 at 10:52:53 PM, 'Dominic Cooney' via blink-dev <blin...@chromium.org> wrote:
>>
>> I think I need a cycles-defeating promise, something like a ScriptPromise with a weak handle and an hidden property from wrapper to promise. Can you give me some implementation pointers?
>>
>> Here's my situation:
>>
>> I have an object, navigator.serviceWorker, that vends promises through a "ready" property.
>>
>> The implementation today is very simple, because it either returns a resolved promise, or never resolves the promise. In both cases it creates a promise and hands it back to the user.
>>
>> In the next step I need to vend a promise that I will resolve later--possibly never.
>
>
> Is there some point at which you know that you'll never resolve the promise?  That's the point at which to break the cycle.  For example, we typically break these cycles when the ActiveDOMObject::stop notification is called.

I think it is the frame navigating. So navigator.serviceWorker, which is already a ContextLifecycleObserver, should simply use that as a signal to relinquish the Promise handles?

You probably need to upgrade from ContextLifecycleObserver to ActiveDOMObject.  The problem with using the contextDestroyed notification is that holding the promise might prevent the context from being destroyed.

> One difficulty with using weak processing to define the point at which the promise will never resolve is that we'll leak some implementation details about when we trigger garbage collection.

Leak implementation details to whom?

Web sites that call this API.  In the future, when we change these implementation details, we run the risk of breaking web sites.  It's better to have predictable behavior that we can maintain over the long haul and that other browsers can implement identically.

Dominic Cooney

unread,
Jun 10, 2014, 12:07:40 PM6/10/14
to Adam Barth, yhi...@chromium.org, blin...@chromium.org, har...@chromium.org


On Jun 10, 2014 8:57 AM, "Adam Barth" <aba...@google.com> wrote:
>
> On Tue Jun 10 2014 at 8:50:19 AM, Dominic Cooney <domi...@google.com> wrote:
>>
>> On Jun 10, 2014 8:09 AM, "Adam Barth" <aba...@google.com> wrote:
>> > On Mon Jun 09 2014 at 10:52:53 PM, 'Dominic Cooney' via blink-dev <blin...@chromium.org> wrote:
>> >>
>> >> I think I need a cycles-defeating promise, something like a ScriptPromise with a weak handle and an hidden property from wrapper to promise. Can you give me some implementation pointers?
>> >>
>> >> Here's my situation:
>> >>
>> >> I have an object, navigator.serviceWorker, that vends promises through a "ready" property.
>> >>
>> >> The implementation today is very simple, because it either returns a resolved promise, or never resolves the promise. In both cases it creates a promise and hands it back to the user.
>> >>
>> >> In the next step I need to vend a promise that I will resolve later--possibly never.
>> >
>> >
>> > Is there some point at which you know that you'll never resolve the promise?  That's the point at which to break the cycle.  For example, we typically break these cycles when the ActiveDOMObject::stop notification is called.
>>
>> I think it is the frame navigating. So navigator.serviceWorker, which is already a ContextLifecycleObserver, should simply use that as a signal to relinquish the Promise handles?
>
> You probably need to upgrade from ContextLifecycleObserver to ActiveDOMObject.  The problem with using the contextDestroyed notification is that holding the promise might prevent the context from being destroyed.

Of course. Thanks for the pointers.

Yutaka Hirano

unread,
Jun 10, 2014, 12:09:18 PM6/10/14
to Adam Barth, Dominic Cooney, Kentaro Hara, blink-dev
You have a ServiceWorker C++ object, its JS wrapper and a ScriptPromiseResolverWithContext, right?
I think you can set the v8 value of the associated Promise as a property of the wrapper.
That solves the resource problem about ScriptPromise / ScriptValue, I think.

Boris Zbarsky

unread,
Jun 10, 2014, 12:09:43 PM6/10/14
to blink-dev
On 6/10/14, 11:54 AM, Anne van Kesteren wrote:
> It should return the same promise. A property that returns a new
> object each time you get it without the environment having changed is
> not good. You want to preserve obj.x === obj.x.

The IDL here is:

Promise<Response[]> ready();

so that's not a concern (unlike the use of Response[], which is).

-Boris

Dominic Cooney

unread,
Jun 10, 2014, 12:14:26 PM6/10/14
to Anne van Kesteren, blink-dev, Kentaro Hara, Yutaka Hirano

The spec for ready says it can resolve with different objects over the lifetime of the page (for example, after replace) so it is sometimes necessary to return a new promise.

I can make Blink return as few as possible. FWIW I don't think I have seen this as a *requirement*.

> --
> http://annevankesteren.nl/

Dominic Cooney

unread,
Jun 10, 2014, 12:16:44 PM6/10/14
to Boris Zbarsky, blink-dev

My original post was about another ready, ServiceWorkerContainer.ready, which I think is Promise<ServiceWorker> IIRC.

Anne van Kesteren

unread,
Jun 10, 2014, 12:20:44 PM6/10/14
to Boris Zbarsky, blink-dev
FWIW, that is outdated. The API guideline (not documented yet) is that
a promise that reports on a state change is returned from a property.
So we'll have document.ready, document.loaded, etc.


--
http://annevankesteren.nl/

Anne van Kesteren

unread,
Jun 10, 2014, 12:22:03 PM6/10/14
to Dominic Cooney, blink-dev, Kentaro Hara, Yutaka Hirano
On Tue, Jun 10, 2014 at 6:14 PM, Dominic Cooney <domi...@google.com> wrote:
> I can make Blink return as few as possible. FWIW I don't think I have seen
> this as a *requirement*.

Note that if there is no requirement either way the specification is
likely bogus. The current service worker specification is extremely
sketchy when it comes to lifetime of objects, what returns what, etc.


--
http://annevankesteren.nl/
Reply all
Reply to author
Forward
0 new messages