Bug 1426908 - Asynchronously enable CodeMirror syntax highlight for large content r?honza draft
authorRicky Chien <ricky060709@gmail.com>
Fri, 05 Jan 2018 17:18:34 +0800
changeset 716221 ed0eedec93ded08b64b863d199f0499eb537cd06
parent 716101 c0972fbe978227d171f2bee66d43ea383b1ddbaa
child 744980 52c7cead8b257aedf99e161ed38d47791f6c7d05
push id94362
push userbmo:rchien@mozilla.com
push dateFri, 05 Jan 2018 10:02:29 +0000
reviewershonza
bugs1426908
milestone59.0a1
Bug 1426908 - Asynchronously enable CodeMirror syntax highlight for large content r?honza MozReview-Commit-ID: v4GcMOnrWy
devtools/client/netmonitor/src/components/SourceEditor.js
devtools/client/netmonitor/src/constants.js
--- a/devtools/client/netmonitor/src/components/SourceEditor.js
+++ b/devtools/client/netmonitor/src/components/SourceEditor.js
@@ -3,66 +3,81 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Component } = require("devtools/client/shared/vendor/react");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const Editor = require("devtools/client/sourceeditor/editor");
-const { SOURCE_EDITOR_SYNTAX_HIGHLIGHT_MAX_SIZE } = require("../constants");
 
 const { div } = dom;
 
 /**
  * CodeMirror editor as a React component
  */
 class SourceEditor extends Component {
   static get propTypes() {
     return {
-      // Source editor syntax hightligh mode, which is a mime type defined in CodeMirror
+      // Source editor syntax highlight mode, which is a mime type defined in CodeMirror
       mode: PropTypes.string,
       // Source editor content
       text: PropTypes.string,
     };
   }
 
   componentDidMount() {
     const { mode, text } = this.props;
 
     this.editor = new Editor({
       lineNumbers: true,
       lineWrapping: false,
-      mode: text.length < SOURCE_EDITOR_SYNTAX_HIGHLIGHT_MAX_SIZE ? mode : null,
+      mode: null, // Disable auto syntax detection, but then we set mode asynchronously
       readOnly: true,
       theme: "mozilla",
       value: text,
     });
 
-    // Delay to CodeMirror initialization content to prevent UI freezed
+    // Delay to CodeMirror initialization content to prevent UI freezing
     this.editorTimeout = setTimeout(() => {
       this.editor.appendToLocalElement(this.refs.editorElement);
+      // CodeMirror's setMode() (syntax highlight) is the performance bottleneck when
+      // processing large content, so we enable it asynchronously within the setTimeout
+      // to avoid UI blocking. (rendering source code -> drawing syntax highlight)
+      this.editorSetModeTimeout = setTimeout(() => {
+        this.editor.setMode(mode);
+      });
     });
   }
 
+  shouldComponentUpdate(nextProps) {
+    return nextProps.mode !== this.props.mode || nextProps.text !== this.props.text;
+  }
+
   componentDidUpdate(prevProps) {
     const { mode, text } = this.props;
 
-    if (prevProps.mode !== mode &&
-        text.length < SOURCE_EDITOR_SYNTAX_HIGHLIGHT_MAX_SIZE) {
-      this.editor.setMode(mode);
-    }
+    if (prevProps.text !== text) {
+      // Reset the existed 'mode' attribute in order to make setText() process faster
+      // to prevent drawing unnecessary syntax highlight.
+      this.editor.setMode(null);
+      this.editor.setText(text);
 
-    if (prevProps.text !== text) {
-      this.editor.setText(text);
+      // CodeMirror's setMode() (syntax highlight) is the performance bottleneck when
+      // processing large content, so we enable it asynchronously within the setTimeout
+      // to avoid UI blocking. (rendering source code -> drawing syntax highlight)
+      this.editorSetModeTimeout = setTimeout(() => {
+        this.editor.setMode(mode);
+      });
     }
   }
 
   componentWillUnmount() {
     clearTimeout(this.editorTimeout);
+    clearTimeout(this.editorSetModeTimeout);
     this.editor.destroy();
   }
 
   render() {
     return (
       div({
         ref: "editorElement",
         className: "source-editor-mount devtools-monospace",
--- a/devtools/client/netmonitor/src/constants.js
+++ b/devtools/client/netmonitor/src/constants.js
@@ -312,15 +312,14 @@ const general = {
   ACTIVITY_TYPE,
   EVENTS,
   FILTER_SEARCH_DELAY: 200,
   UPDATE_PROPS,
   HEADERS,
   RESPONSE_HEADERS,
   FILTER_FLAGS,
   FILTER_TAGS,
-  SOURCE_EDITOR_SYNTAX_HIGHLIGHT_MAX_SIZE: 51200, // 50 KB in bytes
   REQUESTS_WATERFALL,
   PANELS,
 };
 
 // flatten constants
 module.exports = Object.assign({}, general, actionTypes);