Skip to content

Provide a helper method waiting for HTMLElement upgrade to CustomElement#9542

Merged
zhouyx merged 4 commits intoampproject:masterfrom
zhouyx:wait-for-customElement
May 30, 2017
Merged

Provide a helper method waiting for HTMLElement upgrade to CustomElement#9542
zhouyx merged 4 commits intoampproject:masterfrom
zhouyx:wait-for-customElement

Conversation

@zhouyx
Copy link
Copy Markdown
Contributor

@zhouyx zhouyx commented May 25, 2017

For #9126

@zhouyx zhouyx requested a review from dvoytenko May 25, 2017 01:06
src/dom.js Outdated
* Return a promise that resolve when an AMP element upgrade from HTMLElement
* to CustomElement
* @param {!Element} element
* @return {!Promise}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's do !Promise<!Element> for convenience.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

src/dom.js Outdated
* @param {!Element} element
* @return {!Promise}
*/
export function whenUpgradeToCustomElement(element) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

"whenUpgrade_d_ToCustomElement"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

changed name

src/dom.js Outdated
return Promise.resolve();
}
// If Element is still HTMLElement, wait for it to upgrade to customElement
if (!element.upgradeToCustomElementPromise_) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This won't work unfortunately like this. Obfuscation will break between versions. Probably will have to work with "pure" strings.

Copy link
Copy Markdown
Contributor Author

@zhouyx zhouyx May 26, 2017

Choose a reason for hiding this comment

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

Changed to element['upgradedToCustomElementPromise']. But I still don't get why element.upgradeToCustomElementPromise_ will break. I tested locally and it works fine before 😕

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Due to obfuscation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks @dvoytenko for the explanation!! I would never be able to find out myself 😄

/** @private {?./layout-delay-meter.LayoutDelayMeter} */
this.layoutDelayMeter_ = null;

if (this.whenUpgradeToCustomElement_) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

See below, re: strings instead of private properties.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

changed to this['whenUpgradedToCustomElement'], if this is what you mean here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Our current format is smth like __AMP_NAME_OF_FIELD. Let's keep to that format.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

changed to __AMP_UPGRADE_CUS_ELE_PROMISE__ like what we did in action-imp.js

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry to bikeshed. Let's just call __AMP_UPG_PRM and __AMP_UPG_RES.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Haha. You name it!

if (!ad.whenBuilt) {
// TODO(@zhouyx, #9126): Cleanup once make sure the fix works
dev().error(TAG, 'element whenBuilt still do not exist!');
timerFor(this.win).delay(() => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This logic can be flattened:

whenUpgradedToCustomElement().then(ad =>
  if (ad.whenBuilt)
    return ad;
  }
  // TODO
  return timerFor(this.win).promise(1000).then(() => ad);
}).then(ad => {
  return ad.whenBuilt();
}).then(() => {
  this.mutateElement(() => toggle(this.element, true));
});

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I prefer the if/else loop since I am pretty sure it won't get into the if loop. Just add it for extra check, will remove once confirm the fix works.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why do we if (ad.whenBuilt)? We already await upgrade, so it's not needed. Right?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

But the duplication.... 😢

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

haha, I think @dvoytenko is right. it's not needed. I already tested it and am pretty sure it fix the race condition bug in #9126. @jridgewell I deleted the duplication code 😄

// may not be attached yet.
return startsWith(tag, 'AMP-') &&
// Some "amp-*" elements are not really AMP elements. :smh:
!(tag == 'AMP-STICKY-AD-TOP-PADDING' || tag == 'AMP-BODY');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Merge conflict? I thought this was already in there?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You didn't merge that PR 😈

*/
export function whenUpgradedToCustomElement(element) {
dev().assert(isAmpElement(element), 'element is not AmpElement');
if (element.createdCallback) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Use __AMP_RESOURCE, like Resources does.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Does a customElement guaranteed to have a resource at before createdCallback being called?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not guaranteed. Adding it to DOM can happen much much later. So, I think, createdCallback is a good idea.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

👍


if (this['whenUpgradedToCustomElement']) {
this['whenUpgradedToCustomElement'](this);
this['whenUpgradedToCustomElement'] = null;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unset the promise, too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

what promise? element['upgradedToCustomElementPromise']? I am returning it?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Agree. Probably better to clear the promise out.

Copy link
Copy Markdown
Contributor Author

@zhouyx zhouyx May 26, 2017

Choose a reason for hiding this comment

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

set element['promise'] to null. To confirm when I do return element['promise'] it is not returning a reference to the promise? So setting element['promise'] = null later doesn't affect the returned promise from #whenUpgradedToCustomElement function.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shouldn't go to null, but rather delete this['ABC'].

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

👍

this.mutateElement(() => {
toggle(this.element, true);
});
ad.whenBuilt().then(() => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We can unnest:

then(() => {
  return ad.whenBuilt();
}).then(() => {
  this.mutateElement(() => toggle(this.element, true));
});

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

sorry I didn't get it, but what's the need to unnest here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's JS style when using Promises (we needed promises because of callback hell). When using promises, instead of chaining a bunch of #then calls inside a then block, you return the promise instead.

then(() => {
  return ad.whenBuilt().then(() => {
    // this is callback hell
  });
});

//vs
then(() => {
  return ad.whenBuilt();
}).then(() => {
  // left indent is the same, so callback hell is avoided.
});

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I see, changed! Thanks for the explanation! However I don't think we have a style requirement for this, and I can find the second usage in a lot of places😢

@zhouyx zhouyx merged commit e27a195 into ampproject:master May 30, 2017
@zhouyx zhouyx deleted the wait-for-customElement branch May 30, 2017 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants