this.monacoInstance.trigger("editor", "editor.action.formatDocument");这么一看需求还是蛮简单的。
onKeyDown={(event) => { const keyCode = event.keyCode || event.which || event.charCode; const isCtrlOrCmdPressed = event.ctrlKey || event.metaKey; if (keyCode === 83 && isCtrlOrCmdPressed) { this.monacoInstance.trigger("editor", "editor.action.formatDocument"); event.preventDefault(); } }}然后本地测试确实可以格式化代码成功,但是当我将编辑器中代码量增加到1000行以上,故意把格式化错乱,再次点击 Cmd+S/Control+S 保存时,会有卡顿效果。是因为在格式化过程算法实现会进行复杂的语法分析和规则应用,对于大量的代码,进行语法分析和根据格式化规则进行处理可能需要大量的计算资源和时间。需要遍历整个代码树,检查各种语法结构,应用缩进规则、换行规则等,阻塞主进程,那基于这种卡顿场景有什么优化办法呢?
new Worker(new URL('./format.worker.js'),import.meta.url)webpack配置globalObject支持webWorker
output: { globalObject: 'self', // 用于支持 web workers filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), },主线程与worker代码编写
1.创建一个新的 JavaScript 文件,test.worker.js,编写格式化操作
worker 中的格式化操作不再使用 monaco 的 api,改为使用 prettier/standalone 和 prettier/parser-babel 模块。可扩展性更强了,可配置格式化内容。代码如下:
import * as prettier from 'prettier/standalone'; import * as parserBabel from 'prettier/parser-babel'; self.onmessage = function(event) { const { code, parser } = event.data; debugger const formattedCode = prettier.format(code, { parser: parser, plugins: [parserBabel] }); self.postMessage(formattedCode); };2.在主页面中创建和使用 Web Worker
class Editor extends React.Component<IEditorProps,IEditorState>{ private formatterWorker; constructor(props: IEditorProps) { super(props); this.formatterWorker = new Worker(new URL('./formatter.worker.js',import.meta.url)); this.formatterWorker.onmessage = this.handleFormatterWorkerMessage.bind(this); } // 省略组件封装相关代码 handleFormatterWorkerMessage(event){ const formattedCode = event.data; this.monacoInstance.setValue(formattedCode); } render() { const { className, style, options } = this.props; // 省略部分代码 let renderStyle = { width: '100%', height: '100%', overflow: 'auto', minWidth: '1200px', minHeight: '280px', }; renderStyle = style ? Object.assign(renderStyle, style) : renderStyle; return ( <section onKeyDown={(event) => { const keyCode = event.keyCode || event.which || event.charCode; const isCtrlOrCmdPressed = event.ctrlKey || event.metaKey; if (keyCode === 83 && isCtrlOrCmdPressed) { const code = this.monacoInstance.getValue(); this.formatterWorker.postMessage({ code: code, parser: 'babel' }); } }} style={renderStyle} ref={(domIns: any) => { this.monacoDom = domIns; }} /> ); } }注意:WebWorker 创建 this.formatterWorker = new Worker(new URL('./formatter.worker.js',import.meta.url));