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

RichText: Reuse DOM document across calls to createEmpty #12402

Merged
merged 4 commits into from
Nov 30, 2018

Conversation

aduth
Copy link
Member

@aduth aduth commented Nov 28, 2018

Related: #7890 (comment)

This pull request seeks to optimize the behavior of RichText's internal createEmpty implementation for DOM tree operations. It reuses a single reference to a DOM document rather than creating a new instance for each invocation.

Implementation notes:

Using a shared reference could potentially have unintended side effects if the reference is held for later use. Given that this function is internal to the module, I think it's an acceptable compromise. I made an attempt to be as clear as possible about this potential gotcha through inline code comments.

As an aside, I noted that this function is called 6 times for every key press in a paragraph. This is something which should be evaluated for future optimization, but is not strictly relevant to the changes proposed here.

Possibly related: #11602

Testing instructions:

Ensure unit tests pass:

npm run test-unit packages/rich-text

Verify there are no regressions in the general behavior of text input in RichText (e.g. paragraph).

@aduth aduth added [Feature] Rich Text Related to the Rich Text component that allows developers to render a contenteditable [Type] Performance Related to performance efforts labels Nov 28, 2018
@aduth aduth requested a review from ellatrix November 28, 2018 22:13
@aduth aduth added the [Package] Rich text /packages/rich-text label Nov 28, 2018
@ellatrix
Copy link
Member

It seems that one e2e test fails consistently... Most likely some other commit causing it.

FAIL test/e2e/specs/adding-inline-tokens.test.js (32.718s)
  ● adding inline tokens › should insert inline image
    waiting for selector ".media-modal li[aria-label="e6a0d94f-6b73-4fad-9f9d-855089c67602"]" failed: timeout 30000ms exceeded
      39 | 
      40 | 		// Wait for upload.
    > 41 | 		await page.waitForSelector( `.media-modal li[aria-label="${ filename }"]` );
         | 		           ^
      42 | 
      43 | 		// Insert the uploaded image.
      44 | 		await page.click( '.media-modal button.media-button-select' );
      at new WaitTask (node_modules/puppeteer/lib/FrameManager.js:840:28)
      at Frame._waitForSelectorOrXPath (node_modules/puppeteer/lib/FrameManager.js:731:12)
      at Frame.waitForSelector (node_modules/puppeteer/lib/FrameManager.js:690:17)
      at Page.waitForSelector (node_modules/puppeteer/lib/Page.js:1008:29)
      at Object.waitForSelector (test/e2e/specs/adding-inline-tokens.test.js:41:14)
      at tryCatch (node_modules/regenerator-runtime/runtime.js:62:40)
      at Generator.invoke [as _invoke] (node_modules/regenerator-runtime/runtime.js:288:22)
      at Generator.prototype.(anonymous function) [as next] (node_modules/regenerator-runtime/runtime.js:114:21)
      at asyncGeneratorStep (test/e2e/specs/adding-inline-tokens.test.js:21:103)
      at _next (test/e2e/specs/adding-inline-tokens.test.js:23:194)

Copy link
Member

@ellatrix ellatrix left a comment

Choose a reason for hiding this comment

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

Looks good!


### Internal

- `unstableToDom` will no longer create a new DOM document on each call; a single document will be shared across each invocation.
Copy link
Member

Choose a reason for hiding this comment

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

I thought we were not documenting unstable APIs?

Copy link
Member Author

Choose a reason for hiding this comment

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

I hesitated, but ultimately decided that it's good to include something in the CHANGELOG for any pull request.

I wouldn't so much call this out as documenting the unstable API, since a CHANGELOG is not documentation. The "Internal" heading was meant to indicate that it's more a refactoring / housekeeping than anything else.

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe I can revise this a bit to avoid specifically mentioning unstableToDom, while keeping the essence of the note otherwise intact.

// function being internal to `rich-text` (full control in avoiding a risk
// of asynchronous operations on the shared reference), a single document
// is reused and reset for each call to the function.
if ( createEmpty.body ) {
Copy link
Member

Choose a reason for hiding this comment

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

Nice 👍

@ellatrix
Copy link
Member

As an aside, I noted that this function is called 6 times for every key press in a paragraph. This is something which should be evaluated for future optimization, but is not strictly relevant to the changes proposed here.

@aduth I see this only happening once for every key press?

@aduth aduth added this to the 4.7 milestone Nov 30, 2018
@aduth
Copy link
Member Author

aduth commented Nov 30, 2018

@aduth I see this only happening once for every key press?

Judging by #12460, were you able to reproduce? It appears to be resolved after (and only after) that pull request was merged.

Testing diff:

diff --git a/packages/rich-text/src/to-dom.js b/packages/rich-text/src/to-dom.js
index b582c7708..93e4a61e0 100644
--- a/packages/rich-text/src/to-dom.js
+++ b/packages/rich-text/src/to-dom.js
@@ -60,6 +60,7 @@ function getNodeByPath( node, path ) {
 
 function createEmpty() {
 	const { body } = document.implementation.createHTMLDocument( '' );
+	console.count( 'createEmpty' );
 	return body;
 }

@ellatrix
Copy link
Member

@aduth Yes. I mistakenly thought this PR was updating createElement in the same package. That function could use the same logic.

* the value to operate upon asynchronously, as it may have unexpected results.
*
* @return {WPRichTextTree} RichText tree.
*/
function createEmpty() {
Copy link
Member

Choose a reason for hiding this comment

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

There's also createElement, see #12470. It would be great if we could merge these two functions into one?

Copy link
Member

Choose a reason for hiding this comment

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

Maybe we can update the PR here to also address createElement and only keep one.

@aduth aduth force-pushed the update/rich-text-reuse-document branch from de614ed to 038769c Compare November 30, 2018 15:37
@aduth
Copy link
Member Author

aduth commented Nov 30, 2018

@iseulde I cherry-picked f0c9aa5 from #12470 into this branch and added revisions of both #12470 (comment) (bdce846) and #12470 (comment) (f9e9e89).

How does it look?

Copy link
Member

@ellatrix ellatrix left a comment

Choose a reason for hiding this comment

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

Looks good to me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Rich Text Related to the Rich Text component that allows developers to render a contenteditable [Package] Rich text /packages/rich-text [Type] Performance Related to performance efforts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants