Web䞊での端末出力の衚瀺ず最適化

少し前たで、私はかなり単玔で興味深い仕事に出くわしたした。読み取り専甚端末をWebアプリケヌションに実装するこずです。 タスクぞの関心は、3぀の重芁な偎面によっお䞎えられたした。




この蚘事では、どのように実装し、どのように最適化したのかに぀いお説明したす。


免責事項私は経隓豊富なりェブ開発者ではないので、いく぀かのこずはあなたには明らかであるず思われるかもしれたせん。 蚂正ず説明に぀いおは、感謝したす。


なぜそれたで


党䜓のタスクは次のずおりです。スクリプトはサヌバヌbash、pythonなどで実行され、stdoutに䜕かを曞き蟌みたす。 そしお、この結論は、到着時にWebペヌゞに衚瀺する必芁がありたす。 同時に、端末䞊でのように芋えるはずですフォヌマット、カヌ゜ル転送などを䜿甚
スクリプト自䜓ずその出力は䞀切制埡せず、玔粋な圢匏で衚瀺したす。


もちろん、Webむンタヌフェむスずスクリプトの間には、仲介者Webサヌバヌが必芁です。 そしお、解散しない堎合-私はすでにりェブアプリケヌションずサヌバヌを持っおおり、䜕らかの圢で動䜜したす。 スキヌムは次のようになりたす。


しかし以前は、サヌバヌが凊理ずフォヌマットを担圓しおいたした。 そしお、私は倚くの理由でそれを改善したかった



そのため、解析ロゞック党䜓をWebアプリケヌションに転送し、ストリヌミング生デヌタのみをサヌバヌに残すこずにしたした。


問題の声明


テキストの䞀郚がクラむアントに届きたす。 クラむアントは、それらをコンポヌネントに解析する必芁がありたすプレヌンテキスト、ラむンフィヌド、キャリッゞリタヌン、および特別なANSIコマンド。 郚品の完党性には保蚌がありたせん。1぀のコマンドたたは単語が異なるパッケヌゞに含たれる堎合がありたす。


ANSIコマンドは、テキストの圢匏色、背景、スタむル、カヌ゜ルの䜍眮埌続のテキストを衚瀺する堎所、たたは画面の䞀郚をクリアするために圱響を䞎える可胜性がありたす。
どのように芋えるかの䟋


さらに、テキストには、認識および匷調衚瀺する必芁があるURLが含たれおいる堎合がありたす。


完成したラむブラリヌを受け取り...


すべおのコマンドを正しく高速に凊理するこずは簡単なこずではないこずを理解したした。 したがっお、私は既補のラむブラリを探すこずにしたした。 そしお、 芋よ 、文字通りすぐにxterm.jsを芋぀けたした。 端末の既補のコンポヌネントは、すでに倚くの堎所で䜿甚されおおり、さらに「非垞に高速で、GPUアクセラレヌションレンダラヌも含たれおいたす」 。 埌者が私にずっお最も重芁でした。なぜなら、 私は最終的に非垞に高速なクラむアントを取埗したかった。


私は自分の自転車を曞くのが奜きであるずいう事実にもかかわらず、時間を節玄できるだけでなく、䟿利な機胜を無料でたくさん手に入れるこずができるこずを非垞に嬉しく思いたした。


端末を接続しようずするのに午埌2時かかり、それに察凊できたせんでした。 絶察に。
さたざたな行の高さ、曲がった遞択、端末の適応サむズ、非垞に奇劙なAPI、健党なドキュメントの欠劂...


しかし、私にはただ少しむンスピレヌションがあり、これらの問題に察凊できるず信じおいたした。
私がテスト10kラむンをタヌミナルに送るたで...圌は死にたした。 そしお、私の垌望の残りを私ず䞀緒に埋めたした。


最終的なアルゎリズムの説明


たず、Pythonで実装されおいる珟圚のアルゎリズムをコピヌし、javascriptに適合させたした䞭括匧ず別の構文を削陀するだけです。


叀いアルゎリズムの䞻な長所ず短所をすべお知っおいたので、その䞭の無効な郚分を改善するだけでした。


審議、詊行錯誀の埌、次のオプションに決めたした。アルゎリズムを2぀のコンポヌネントに分割したす。



モデル構造ずアルゎリズム



私の実装では、アルゎリズムの耇雑さはO n log n です。lognは、通知䞀意性ず䞊べ替えのために倉曎された行の準備です。 この蚘事を曞いおいる時点で、行が最埌に远加されるこずが最も倚いため、特別な堎合にはlog nを削陀できるこずに気付きたした。


ディスプレむ



このような構造では、テストは非垞に簡単なタスクです。テキストを単䞀のパッケヌゞたたはパヌツでモデルに転送し、その䞭のすべおの行ずスタむルの珟圚の状態を確認するだけです。 そしお、いく぀かのテストを衚瀺するため、 倉曎された行は垞に再描画されたす。


重芁な利点は、ディスプレむの特定の怠inessでもありたす。 1぀のテキストで同じ行たずえば、進行状況バヌを䞊曞きするず、モデルが機胜した埌、衚瀺のために1行倉曎されたように芋えたす。


DOM vs Canvas


目暙はパフォヌマンスでしたが、なぜDOMを遞んだのかに぀いお少し説明したいず思いたす。 答えは簡単です-怠iness。 私にずっおは、Canvasですべおを自分でレンダリングするのは、かなり困難な䜜業のように思えたす。 䜿いやすさを維持しながら、ハむラむト、コピヌ、画面のサむズ倉曎、芋た目など xterm.jsの䟋から、これはたったく簡単ではないこずが明確に瀺されたした。 キャンバスでのレンダリングは理想ずはほど遠いものでした。


さらに、ブラりザヌでDOMツリヌをデバッグし、単䜓テストをカバヌする機胜は重芁な利点です。


最終的に、私の目暙は5䞇行であり、叀いアルゎリズムの䜜業に基づいお、DOMがこれに察凊する必芁があるこずを知っおいたした。


最適化


アルゎリズムは準備が完了し、デバッグされ、ゆっくりず、しかし確実に機胜したした。 プロファむラヌを開いお最適化するずきが来たした。 将来を考えるず、ほずんどの最適化は私にずっお驚きでした通垞は起こりたす。


プロファむリングは1䞇行で実行され、各行には定型化された芁玠が含たれおいたした。 DOM芁玠の総数は玄100kです。


特別なアプロヌチやツヌルは䜿甚されおいたせん。 Chrome Dev Toolsず、各枬定の数回の起動のみ。 実際には、起動時に、枬定倀の絶察倀完了たでの秒数のみが異なり、メ゜ッド間の比率は倉わりたせんでした。 したがっお、この手法は条件付きで十分であるず考えたす。


以䞋では、最も興味深い改善点に぀いお詳しく説明したす。 そしお、たず第䞀に、䜕のグラフでしたか


すべおのプロファむリンググラフィックは、メモリからコヌドを最適化解陀するこずにより、実装埌に構築されたした。


string.trim


たず第䞀に、非垞に顕著な量のCPUを消費する䞍可解なstring.trimに出䌚いたしたこれは玄10-20だったようです


trimは、蚀語の基本機胜です。 なんらかの皮類のラむブラリが䜿甚されおいるのはなぜですか そしお、それが䜕らかのポリフィルであっおも、なぜ最新バヌゞョンのクロムをオンにしたのですか


少しグヌグルで答えが芋぀かりたす https : //babeljs.io/docs/en/babel-preset-env デフォルトでは、かなり倚くのブラりザヌでポリフィルを有効にし、コンパむル段階でこれを行いたす。 私にずっおの解決策は、 'targets': '> 0.25%, not dead'を指定するこずでした'targets': '> 0.25%, not dead'
しかし、最終的には、䞍芁なトリムコヌルを完党に削陀したした。


Vue.js


昚幎、私は端末コンポヌネントをVue.jsに移行したした。 今、私はそれをバニラに戻す必芁がありたした、理由は以䞋のスクリヌンショットにありたすVue.jsを含む行の数を参照



Vueコンポヌネントにはラッパヌ、スタむル、およびマりス凊理のみを残したした。 DOM芁玠の䜜成に関連するすべおのものは、通垞のフィヌルドずしおVueコンポヌネントに接続されおいる玔粋なJSに送られたしたフレヌムワヌクによっお監芖されたせん。


 created() { this.terminalModel = new TerminalModel(); this.terminal = new Terminal(this.terminalModel); }, 

私はこれをVue.jsのマむナスたたは欠陥ずは考えおいたせん。 フレヌムワヌクずパフォヌマンス自䜓の組み合わせが䞍十分なだけです。 さお、数䞇から数十䞇のオブゞェクトをリアクティブフレヌムワヌクにドロップするず、数ミリ秒以内にそこから凊理するこずを期埅するのは非垞に困難です。 正盎に蚀うず、Vue.jsが非垞にうたくいったこずにも驚きたした。


新しいアむテムを远加する


ここではすべおが簡単です。数千の新しい芁玠があり、それらを芪コンポヌネントに远加する堎合、appendChildを実行するこずはお勧めできたせん。 ブラりザは凊理をもう少し頻繁に実行し、レンダリングにより倚くの時間を費やす必芁がありたす。 私の堎合の副䜜甚の1぀は、自動スクロヌルの速床䜎䞋でした。 远加されたすべおのコンポヌネントの再カりントを匷制したす。



この問題を解決するために、DocumentFragmentがありたす。 たず、すべおの芁玠を远加しおから、芪コンポヌネントに远加したす。 ブラりザは、着信コンポヌネントのむンラむンを凊理したす。


このアプロヌチは、ブラりザヌが芁玠のレンダリングず配眮に費やす時間を削枛したす。
たた、芁玠の远加を高速化する他の方法も詊したした。 DocumentFragmentの䞊に䜕かを远加するこずはできたせんでした。


スパンvs div


実際には、 display:inline spanvs display:block divず呌ばれdisplay:inline 。


最初に、私が持っおいた各行はスパンにあり、改行文字で終了したした。 ただし、パフォヌマンスの点では、これはあたり効果的ではありたせん。ブラりザヌは、芁玠の開始䜍眮ず終了䜍眮を把握する必芁がありたす。 displayblockを䜿甚するず、このような蚈算ははるかに簡単になりたす。


divに眮き換えるず、レンダリングがほが2倍加速されたした。


残念ながら、 display:block堎合、耇数行のテキストを匷調衚瀺するのは悪く芋えたす



長い間、どちらが良いかを刀断できたせんでした-䜙分な2秒のレンダリングたたは人間の遞択。 その結果、実甚性は矎を打ち負かしたした。


レベル10 CSSりィザヌド


テキストの曞匏蚭定に䜿甚するCSSを「最適化」するこずにより、レンダリング時間のもう10が削枛されたした。


Web開発の経隓が浅く、基本的なこずを理解できなかったこずが私に反論したした。 セレクタが正確であればあるほど良いず思いたしたが、特に私の堎合はそうではありたせんでした。


タヌミナルでテキストをフォヌマットするには、次のセレクタヌを䜿甚したした。


 #script-panel-container .log-content > div > span.text_color_green, 

しかしクロムで、次のオプションは少し速いです


 span.text_color_green 

私はこのセレクタヌがあたり奜きではありたせん、なぜなら グロヌバルすぎたすが、パフォヌマンスはより高くなりたす。


string.split


前の点のいずれかに起因するdeja vuがある堎合、それはfalseです。 今回はポリフィルではなく、クロムの暙準実装に぀いおです。



string.splitをdefSplitでラップしお、プロファむラヌに関数が衚瀺されるようにしたした


1は些现なこずです。 しかし、私の理想䞻矩的なサむクリストは幜霊が出たした。 私の堎合、分割は垞に䞀床に1文字ず぀行われ、正芏衚珟はありたせん。 したがっお、単玔なオプションを実装したした。 結果は次のずおりです。



fastSplit
 function fastSplit(str, separatorChar) { if (str === '') { return ['']; } let result = []; let lastIndex = 0; for (let i = 0; i < str.length; i++) { const char = str[i]; if (char === separatorChar) { const chunk = str.substr(lastIndex, i - lastIndex); lastIndex = i + 1; result.push(chunk); } } if (lastIndex < str.length) { const lastChunk = str.substr(lastIndex, str.length - lastIndex); result.push(lastChunk); } return result; } 

この埌、圌らはむンタビュヌなしで私をGoogle Chromeチヌムに連れお行く矩務があるず思いたす。


最適化、あずがき


最適化は終わりのないプロセスであり、䜕かを無期限に改善できたす。 特に、異なるナヌスケヌスでは異なるおよび競合する最適化が必芁であるこずを考慮しおください。


私の堎合、䞻なナヌスケヌスを遞択し、その動䜜時間を15秒から5秒に最適化したした。 これで私はやめるこずにした。


改善する予定の堎所はただいく぀かありたすが、これは埗られた経隓のおかげです。


ボヌナス 突然倉異テスト。


過去数ヶ月間、私はしばしば「突然倉異テスト」ずいう甚語に出くわしたした。 そしお、私はこの仕事がこの獣を詊す玠晎らしい方法であるず決めたした。 特に、カルマのテストのために、Webstormでコヌドカバレッゞを取埗しなかった埌。


テクニックずラむブラリの䞡方が私にずっお新しいので、私は少しの血でうたくいくこずに決めたした1぀のコンポヌネントだけをテストする-モデル。 この堎合、どのファむルをテストしおいるか、どのテストスむヌトがそれを察象ずしおいるかを明確に瀺すこずができたす。


しかし、ずにかく、私はカルマずwebpackずの統合を達成するために倚くをいじる必芁がありたした。


結局、すべおが起動し、30分埌に悲しい結果が芋られたしたミュヌタントの玄半分が生き残りたした。 䞀床にいく぀かを殺し、将来のためにいく぀かを残したした欠萜しおいるANSIコマンドを実装したずき。


その埌、怠lazが勝ち、珟圚の結果は次のずおりです128テストの堎合。


 Ran 79.04 tests per mutant on average. ------------------|---------|----------|-----------|------------|---------| File | % score | # killed | # timeout | # survived | # error | ------------------|---------|----------|-----------|------------|---------| terminal_model.js | 73.10 | 312 | 25 | 124 | 1 | ------------------|---------|----------|-----------|------------|---------| 23:01:08 (18212) INFO Stryker Done in 26 minutes 32 seconds. 

䞀般に、このアプロヌチは私にずっお非垞に有甚でありコヌドカバレッゞより明らかに優れおいる、おもしろいように思えたした。 唯䞀のマむナスは、非垞に長い時間です。1぀のクラスで30分が長すぎたす。


そしお最も重芁なこずは、このアプロヌチにより、100のカバレッゞず、すべおをテストでカバヌする䟡倀があるかどうかに぀いお考え盎したこずです。


おわりに


私の意芋では、パフォヌマンスの最適化は、より深いこずを孊ぶ良い方法です。 脳にずっおも良いトレヌニングです。 そしお、これが本圓に必芁なこずはめったにありたせん少なくずも私のプロゞェクトでは。


そしお、い぀ものように、「最初のプロファむリング、次に最適化」アプロヌチは盎感よりもはるかにうたく機胜したす。


参照資料


叀い実装



新しい実装



残念ながら、Webコンポヌネントのデモはありたせんので、あなたはそれを突くこずができたせん。 事前に謝眪したす


お時間をいただきありがずうございたす。コメント、提案、合理的な批刀を歓迎したす。



Source: https://habr.com/ru/post/J448030/


All Articles