Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add entryType-specific parameters for observe() #104

Closed
wants to merge 8 commits into from

Conversation

npm1
Copy link
Contributor

@npm1 npm1 commented Jul 24, 2018

This PR adds a PerformanceEntryObserverOptions dictionary where entryType-specific parameters are used. The buffered flag is moved to this dictionary. Some <i> tags are changed to <var>. Observe() is updated to consider dictionaries. Queueing an entry is modified to allow passing in a closure. This is in preparation for adding thresholds to certain entry types. Solves #103
@igrigorik @tdresser @toddreifsteck PTAL


Preview | Diff

npm1 added 2 commits July 24, 2018 13:21
This PR adds a PerformanceEntryObserverOptions dictionary where entryType-specific parameters are used. The buffered flag is moved to this dictionary. Some <i> tags are changed to <var>. Observe() is updated to consider dictionaries. Queueing an entry is modified to allow passing in a closure. This is in preparation for adding thresholds to certain entry types. Solves w3c#103
Per comment by @tdresser, instead of using a closure we refer to an optionally defined algorithm, similar to how its done in https://dom.spec.whatwg.org/#concept-node-clone-ext.
index.html Outdated
};
</pre>
<dl>
<dt><dfn>entryTypes</dfn></dt>
<dd>A list of entry types to be observed. The list MUST NOT be empty
and types not recognized by the user agent MUST be ignored.</dd>
</dl>
<p class="note">Whenever a new kind of <a>PerformanceEntry</a> is defined, this
dictionary should be augmented to include a new optional
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is "this dictionary"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in the section titled 'PerformanceObserverInit dictionary' so I think it's clear enough? To reduce ambiguity I could replace that with 'the PerformanceObserverInit dictionary'.

index.html Outdated
<var>should append to observer</var> which receives a <a>PerformanceEntry</a> and
a <a>PerformanceObserver</a> as input and returns a boolean specifying whether the
observer should be notified of the entry.
<p>The <dfn>queue a PerformanceEntry</dfn> <var>new entry</var> with an optional
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following the grammar of this sentence.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, which? The one starting with Specifications, or with 'The queue'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely The queue sentence is incorrect. The first word should be 'To'.

index.html Outdated
<a data-lt="PerformanceObserverInit.entryTypes">entryTypes</a> includes it or it
has a dictionary with that name.</li>
<li><var>should append to observer</var>(<var>new entry</var>,
<var>observer</var>) returns true, if defined by the <i>specification</i> of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For cloning steps, I thought there was an inheritance like approach taken, where specs could override the default. That feels a bit slicker than what we've got here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm no, I don't think there is a default. The closure approach has a default, the cloning steps approach says that a specification may specify additional steps that should be run at a certain point in time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right!

Less ambiguous, fix typo
Copy link
Contributor

@tdresser tdresser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this LGTM.

We should get other folks to take a look though.

index.html Outdated
<a data-lt="PerformanceObserverInit.entryTypes">entryTypes</a> includes it or it
has a dictionary with that name.</li>
<li><var>should append to observer</var>(<var>new entry</var>,
<var>observer</var>) returns true, if defined by the <i>specification</i> of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right!

@npm1
Copy link
Contributor Author

npm1 commented Aug 1, 2018

Ping Ilya and Todd (or who else could be a good reviewer for this?)

index.html Outdated
// retrieve buffered events and subscribe to new events
// for Resource-Timing and User-Timing
// subscribe to new events for Resource-Timing and User-Timing
// and retrieve buffered events from Resource-Timing
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably worth spelling out explicitly what's going on here. Specially, that providing names to entryTypes enables monitoring for said type, initialized with some default settings (e.g. buffered = false). Alternatively, you can specify the entryType name as a key and provide a dictionary with custom settings — e.g. resource : {buffered: true}.

On that note, @toddreifsteck @yoavweiss would love to get your sanity check and review on this pattern.

index.html Outdated
sequence.</li>
<li>For each dictionary of name <var>entryType</var> in <var>options</var>,
add the string `<var>entryType</var>` to <var>entry types</var>.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I grok what this is doing. What is an example of "each dictionary of name entryType"? :-)

I think you're enumerating the keys in options and adding them to entryTypes? As an aside, can we actually do this without first cloning the options? As in, I don't think we should be modifying the passed in object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, maybe enumarating keys in options is clearer? Or enumerating keys whose values are dictionaries (to exclude entryTypes itself for example)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per later comment, I don't think we should be modifying this object in place.. But if we're cloning it first, we could: pluck entryTypes out first and <do-stuff>, then enumerate the remaining keys and <do-more-stuff>, arriving at a consistent internal object that we can use later in the algorithm?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, so I propose adding something like "Each PerformanceObserver gets an associated |entry types| object". Then here we would modify observer's |entry types| instead of some variable of option's entryTypes array. Does that sound reasonable?

index.html Outdated
the <a>PerformanceObserverInit</a> dictionary should be augmented to
include a new optional <a>PerformanceEntryObserverOptions</a> dictionary
with the name of the new <a data-lt="PerformanceEntry.entryType">
entryType</a>.</p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't do this today for existing types. If we follow this recommendation, than we should do so.

That said, we've also tried to explicitly avoid enumerating "valid types" in Performance Timeline, as that makes a hard dependency for the perf timeline to be revved whenever we add a new type. Per discussion in #77, the idea is to have other specs call into Perf Timeline to register available types. The logic here should then enumerate the dictionary members, compare against registered + known types and proceed accordingly. This also means that we ignore any unknown types in this algorithm.

WDYT, does that make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not forcing PerformanceTimeline to be modified whenever a new entry type is added. I was thinking the new spec could do something along the lines of 'partial interface' to add the new dictionary corresponding to its entry type. We already "remove all unsupported types", which is a bit hand-wavy but I think it's clear what it means. If we want to make it a bit more formal, we can go with your registration approach, I just don't know if it adds much clarity or if it makes speccing new entry types easier.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I'm with you now. I like that, that's much cleaner than I what I had in mind before. The one bit I'd change in this proposal is, instead of extending the PerformanceObserverInit we wanted + need to introduce performance.entryTypes and that's the interface the various specs should be extending. In turn, we can then filter passed options to PerformanceObserverInit against said interface.

WDYT, does that make sense? If you're on board with that.. the changes are coupled, and we would need to land the performance.entryTypes proposal first, and then rebase this against that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't follow what you're suggesting here... performance.entryTypes will only help in knowing which are the entry types that are supported globally (implemented by the browser), right? So we still need a way to specify what filters can be used for each entry type, unless we want to support the same set of filters for all entry types? Even if we have the same set of filters on all entry types, we still need to augment PerformanceObserverInit with the dictionaries per entry type (I don't think we want to allow it to contain dictionaries like 'longtask' and 'mark' without specifying them anywhere explicitly). The only alternative I can think of that avoids this would be to have something like this:

dictionary PerformanceObserverInit {
  required sequence<DOMString> entryTypes;
  PerformanceEntryObserverOptions filters;
}

But this would force an observer to apply the same set of filters to all of the observed entry types that it is observing. This is kind of what we're trying to avoid here, since ideally we'd like entryType-specific parameters. If we don't have that, we might as well just keep adding the filters to PerformanceObserverInit directly. WDYT?

@@ -436,30 +452,39 @@ <h2><dfn>disconnect()</dfn> method</h2>
<h2>Processing</h2>
<section data-link-for="PerformanceObserver">
<h2>Queue a <code>PerformanceEntry</code></h2>
<p><i>Specifications</i> of performance entries may define an algorithm
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe our plan was to have this on by default for all types prior to onload, and no buffering afterwards. If that's the case, I believe we wouldn't need this — correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is about the queue algorithm, not about buffering. An example of where we need this is LongTasks thresholds: we need the spec to provide an algorithm to determine if an entry should be added to an observer (look at the entry's duration, compare with the observer's threshold).

optional <var>add to performance entry buffer</var> flag, which is unset
by default, run these steps:</p>
optional <var>add to performance entry buffer</var> flag, which is unset by
default, run these steps:</p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step should be with respect to before or after onload, not the passed in flag.

For context, we ruled out the flag approach because it would, once again, require updating every upstream spec to have this on by default.. and I can't think of cases where we'd want this to be off by default for before-onload.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but I haven't added this flag, it's currently in the spec. How about we do a separate PR for this independent change?

index.html Outdated
<li><var>new entry</var>’s <a data-lt="PerformanceEntry.entryType">entryType</a>
value is in <var>observer</var>'s <a>PerformanceObserverInit</a>: either its
<a data-lt="PerformanceObserverInit.entryTypes">entryTypes</a> includes it or it
has a dictionary with that name.</li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we doing this here again, if we're modifying entryTypes and adding names to it earlier? Could we preprocess this earlier (either unroll entryTypes into the array with default dicts, or the reverse) and reuse that here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We did this in observe() to the |options| parameter, and now that is gone. I would propose having an internal variable within PerformanceObserver that consists of a list of supported entry types. The list could be populated during observe() and then it could be used here, in the queue an entry algorithm. This is probably how implementations do it anyways. WDYT?

@@ -366,14 +380,27 @@ <h2><dfn>PerformanceObserverInit</dfn> dictionary</h2>
<pre class="idl">
dictionary PerformanceObserverInit {
required sequence&lt;DOMString&gt; entryTypes;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking we may want to remove the 'required' from |entryTypes| as well as you could specify what you want to observe using the other dictionaries.

@npm1
Copy link
Contributor Author

npm1 commented Aug 22, 2018

By the way I've added the 'supported entry types' and addressed all comments.
@yoavweiss @toddreifsteck any thoughts on the pattern used on observe() here?

index.html Outdated
@@ -298,6 +300,9 @@ <h2>The <dfn>PerformanceObserver</dfn> interface</h2>
<li> A <a>PerformanceEntryList</a> object called the <dfn>observer
buffer</dfn> that is initially empty.
</li>
<li>A sequence of strings called <dfn>supported entry types</dfn> that is
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/supported entry types/observed entry types/?

I think we should reserve supported entry types for the global "which entry types does performance timeline support"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// Subscribe to new events for User-Timing (marks and measures) via the
// |entryTypes| array. The entry-type specific flags are set to their
// default values for these entry types. Also subscribe to and retrieve
// buffered events from Resource-Timing.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where's the resource-timing part? It's no longer observed, is it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean in the description, or in the code? In the description, we have at the end "Also subscribe to and retrieve buffered events from Resource-Timing." In the code, per this PR the existence of a dictionary 'resource' implies that this PerformanceObserver observes that entry type.

index.html Outdated
<li>Set <a>supported entry types</a> to a copy of <var>options</var>'
<a>entryTypes</a> sequence.
</li>
<li>For each key <var>entryType</var> in the <var>options</var> dictonary that
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/dictonary/dictionary/

agent SHOULD notify developers if <var>entry types</var> is modified.
For example, a console warning listing removed types might be appropriate.</li>
<li>If the resulting <var>entry types</var> sequence is an empty sequence,
<li>Set <a>observed entry types</a> to a copy of <var>options</var>'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be better to explicitly state what the options variable is a line above that.
e.g. "Let options be the input PerformanceObserverInit object" or something along those lines

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I think you meant "observed entry types" to be a var, not a link

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added what observer() receives. I really do mean a link to the associated concept of the PerformanceObserver, not a local var. So is correct in this context.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*so <a> is correct

index.html Outdated
<li>Set <a>observed entry types</a> to a copy of <var>options</var>'
<a>entryTypes</a> sequence.
</li>
<li>For each key <var>entryType</var> in the <var>options</var> dictonary that
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/dictonary/dictionary/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

index.html Outdated
</li>
<li>For each key <var>entryType</var> in the <var>options</var> dictonary that
is not <a>entryTypes</a>, add the string <var>entryType</var> to
<a>observed entry types</a>.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear to me what this does and why. Can you explain?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is: add the entry types that are listed as dictionaries in 'options' to the set of entry types that are observed by this observer. In the example in the code, we had:

observer.observe({
  entryTypes: ["mark", "measure"],
  resource : {buffered: true}
});

In this case, there is a resource dictionary. So this step means: since the key resource is present, add 'resource' to the list of observed entry types.

I think @igrigorik wanted your opinion on whether this is sane or not. If we think this is too ugly, we can remove this part, so that all entry types to be observed must still be listed in the entryTypes array.

index.html Outdated
is not <a>entryTypes</a>, add the string <var>entryType</var> to
<a>observed entry types</a>.
</li>
<li>Remove all unsupported types from <a>observed entry types</a>. The user
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we define somewhere what are the supported types? Can we point to such a definition?
Also, can you rewrite that as an iteration over the sequence?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not define this (this is browser-dependent). If/when we expose performance.entryTypes then we can point to that, but for now I think we don't have a definition. Rewrote as an iteration (although note that this wording was already present before this PR).

<var>entry type</var> in <var>entry types</var> sequence:
<li>For each <var>entry type</var> in <a>observed entry types</a>, if the
<a data-link-for="PerformanceEntryObserverOptions">buffered</a> flag is set
in <var>options</var>' dictionary named <var>entry type</var>:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

options is a PerformanceObserverInit, right? Or is it PerformanceEntryObserverOptions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but buffered would be inside the PerformanceEntryObserverOptions corresponding to that entry type (if it exists), which is itself inside the PerformanceObserverInit options. I moved this flag so that it can be an entryType-specific parameter.

index.html Outdated
<p class="note">Whenever a new kind of <a>PerformanceEntry</a> is defined,
the <a>PerformanceObserverInit</a> dictionary should be augmented to
include a new optional <a>PerformanceEntryObserverOptions</a> dictionary
with the name of the new <a data-lt="PerformanceEntry.entryType">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear what you mean by "the name of the new entryType". Can you be more explicit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean is that PerformanceObserverInit needs to be augmented for example if we were adding EventTiming with entries that have entryType 'event':

partial dictionary PerformanceObserverInit {
   optional PerformanceEntryObserverOptions event;
}

I reworded that last part, is it better now?

@rniwa
Copy link

rniwa commented Sep 7, 2018

I don't think this approach fits *Observer pattern well. See my comment in #103 (comment).

@npm1
Copy link
Contributor Author

npm1 commented Sep 7, 2018

I'm open to changing the shape of the API but we probably want something that is backwards compatible. Changing observe() to only allow specifying one type per observe() call isn't.

@rniwa
Copy link

rniwa commented Sep 8, 2018

We can support both. Either specify a list of types to observe, or specify a type and it's options.

@npm1
Copy link
Contributor Author

npm1 commented Oct 4, 2018

I'm closing this PR and later sending a new one based on the discussion in #103

@npm1 npm1 closed this Oct 4, 2018
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.

5 participants