-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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 amp-story-page element #11510
Add amp-story-page element #11510
Conversation
|
||
|
||
|
||
export class PageElement { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an interesting file. Was adding functionality/events to existing classes like amp-img.js
not tenable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure whether the information we're seeking is general-purpose enough to port to those classes. We very likely need some kind of definition of "loaded" that is specific to amp-story
, as the tradeoff between seeing loading indicators vs. seeing stuttering video is likely different in the story use-case than the article use-case.
/** | ||
* The delay (in milliseconds) to wait between polling for loaded resources. | ||
*/ | ||
const LOAD_TIMER_POLL_DELAY_MS = 250; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems coarse and will probably add ~125ms latency due to imprecision. Is avoiding polling altogether possible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, should be possible. The first pass at this implementation used browser events (e.g. canplaythrough
, loadeddata
, and progress
) and that didn't work well (seems like in practice, browsers differ pretty greatly in how they implement this, and it results in pretty poor results, especially on Android Chrome).
An intermediate implementation used events from each PageElement
to the AmpStoryPage
, but each element polled internally, since there were no events that got us the desired result. The code written here was a refactor of that to allow only creating a single timer per page, rather than a single timer per element (n
timers per page).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. Consider including this under an area for future optimization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed #11532
this.element.appendChild(loadingScreen); | ||
|
||
// Build a list of page elements and poll until they are all loaded. | ||
this.pageElements_ = PageElement.getElementsFromPage(this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we know how performant this is in practice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a timeout (8s), but in practice it seems to be working reasonably, depending on the elements on the page.
We need to do something like this, though; having all the descendants loaded asynchronously whenever they are ready doesn't work well for this format. A potential future optimization is to use the hero
attribute (or similar) to allow publishers to mark up which element(s) to wait for, but I think we'll need to default to a conservative approach, as partially loaded pages are very problematic for the format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
8ms I hope? 😅 Is that on a workstation with CPU throttling or on a low-end mobile device?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I guess it depends which part you're asking about the performance of. I don't think we've evaluated the performance of the PageElement.getElementsFromPage(this)
call, but if you're talking about the comment // Build a list of page elements and poll until they are all loaded.
, then that's what has the 8s timeout. We'll show a loading indicator/screen for up to 8s after the user has started looking at the screen. It takes so long because we're actually waiting for the assets (i.e. mostly videos) to be fetched over the network.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. I was actually curious about the DOM queries. Generally we try to avoid DOM scans in favor of custom element API. For instance, forms would be more robust to dynamic markup changes (e.g. new form elements created from amp-list) if it used an <amp-form>
instead of <form>
as it does now.
We could devise a kind of dynamic add-on system to avoid the need for scanning here. Only justifiable if the scan is slow or we foresee dynamic markup in STAMP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some small things that can be fixed. As discussed, feel free to address these in follow-up PRs.
* @return {!Promise} | ||
* @private | ||
*/ | ||
maybeApplyFirstAnimationFrame() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suffix private functions with _
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was meant to be public
} | ||
} | ||
|
||
/** */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please document this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
|
||
/** | ||
* @return {boolean} True if animations were stopped. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@private
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually unused; deleted
|
||
/** | ||
* Initializes the loading screen for this amp-story-page, and the listeners | ||
* to remove it once loaded. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@private
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
|
||
/** | ||
* Marks any AMP elements that represent media elements with preload="auto". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@private
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
isVideoInterfaceVideo_(el) { | ||
// TODO(newmuis): Check whether the element has the | ||
// i-amphtml-video-interface class, after #11015 from amphtml is merged | ||
// into amphtml-story. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be fixed now.
* advance. | ||
* @param {?Element} el | ||
* @param {!function()} callback | ||
* @return {!Element} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function doesn't seem to return anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
this.element.appendChild(loadingScreen); | ||
|
||
// Build a list of page elements and poll until they are all loaded. | ||
this.pageElements_ = PageElement.getElementsFromPage(this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
8ms I hope? 😅 Is that on a workstation with CPU throttling or on a low-end mobile device?
class VideoInterfaceElement extends PageElement { | ||
constructor(element, page) { | ||
super(element, page); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: Can be removed.
/** | ||
* The delay (in milliseconds) to wait between polling for loaded resources. | ||
*/ | ||
const LOAD_TIMER_POLL_DELAY_MS = 250; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. Consider including this under an area for future optimization.
I think this is ready to be merged once the dependency PR #11509 is merged. |
Implements the page level of the
amp-story
component.Depends on #11330, #11485, #11509, and #11525