Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
12
Help us understand the problem. What is going on with this article?
@haruna-nagayoshi

レンダリングを妨げるJavaScriptとCSSを削除するためにやったこと

概要

「ページの表示速度をあげるため、JavaScriptやCSSファイルがレンダリングを妨害しないようにする」
という目的にたいして調べたことをまとめる。

分析ツール

ページ表示速度を測定するために Lighthouse を利用しており、
分析結果の Eliminate render-blocking resources を減らすことがゴール。
Lighthouseは、Chrome検証モードのAuditsタブからも利用できる。
image.png

PageSpeed Insights(PSI)はlocalやstaging環境では利用できないが、
PSIの分析エンジンとして Lighthouse を使用しているため、Lighthouse を利用すると参考にしやすいかも。
(Lighthouse と PSI は、以前は異なる仕組みでパフォーマンスを測定していたため、チェックする指標は同一ではなく、同じ指標だったとしても計測結果が異なることがあったらしい。)
Lighthouseの監査基準
PageSpeed Insights、Lighthouse の使用を開始しました

レンダリングとは

簡単にいうと、HTMLなどの文字データを読み取って、文字ではなく画面や画像を表示すること。

ブラウザは、ページを表示する前にHTMLを解析して DOM ツリー(xmlやhtmlドキュメントをツリー構造として表現したもの)を構築する。
この処理の途中でスクリプトが存在すると、HTMLの解析を一旦停止してスクリプトを読込・実行するため、
ページが最初に表示されるまでに時間がかかる。

レンダリングを妨害しないようにするには

JavaScript

こういうコードがあったとき、

<script src="common.js">

 
async属性をつけると、スクリプトは非同期に読込・実行される。 

<script src="common.js" async>

 
defer属性をつけると、HTMLの解析完了後かつ DOMContentLoaded が発生する前に実行する。
実行を遅延(defer)させているイメージ。
また、この属性を付与すると、記述した順番で実行されるため、
ライブラリなど依存するファイルがある場合は、defer属性を用いて親ファイルから記述していけばよい。

<script src="jquery.js" defer>
<script src="common.js" defer>
<script src="header.js" defer>

 
scriptは </body> の直前に書けば先にHTMLが分析されてページ表示速度が早くなるという情報がネットにあり、そういうものと思っていたが、
Lighthouse で分析してみるとまったく関係なかった。
どこに記述しようが async/defer 属性が無ければHTMLの解析を止めてスクリプトを読み込むため、
Eliminate render-blocking resources にカウントされる。

MDN script : スクリプト要素
MDN HTMLScriptElement

CSS

こういうコードがあったとき、

<link rel="stylesheet" href="style.css">

 
rel 属性に preload を使用すると、非同期で読み込まれる。
as 属性にリソースの種類を指定しなければならない。

<link rel="preload" href="style.css" as="style">

 
pleload は、Firefox等、対応していないブラウザがあるため、使用の際は注意する。
今回はFirefoxにも対応する必要があったため利用しなかった。検証も行っていない。

MDN rel="preload" によるコンテンツの先読み

async / defer 検証の違いを検証してみる

以下のHTMl、JSを作成して検証する。

async_defer_test.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>実行順序テスト</title>
    <script src="js1.js" defer></script>
    <script src="js2.js" defer></script>
    <script src="js3.js" defer></script>
</head>
<body>
</body>
</html>
js1.js
console.log(111)
js2.js
console.log(222)
js3.js
console.log(333)

結果

asyncだと、リロードするたびにバラバラ。
deferだと、何回リロードしても、111、222、333の順でconsoleに表示される。

詰まったこと

  • 自分で試すという選択肢がなかったこと

簡単に確認できる内容だけど、
調べている最中は、async/deferの動作に確信が持てず、混乱したので先輩に助けを求めた。
「適当にhtmlとjs作って試してみたら?」
と言われて、た、たしかに・・・!と思った。
詰まったら大体、「公式サイトを確認する」「ネットで調べる」「誰かに聞く」ので、
自分で試すことを思いつかなかった。
 

  • consoleでエラーを確認できることを忘れていたこと

ひと通り調べた後、試しにすべてのJSファイルにasync属性をつけたり、逆にすべてにdefer属性をつけたが、
ヘッダーが表示されなくなったり、スライドが動かなくなったりした。
ということは、ライブラリのような、他に依存されているJSが先に(非同期に)読み込まれることにより、正常に動作しなくなったと考えられる。

今回対応した案件では、
HTMLを描画しているJSがライブラリや他のJSに依存しているので、ライブラリなど一部のJSを非同期に読み込むことができない。
(JSでHTMLを描画するのはどれくらい一般的なんだろう・・・。)
async または defer を付加すると次のようなエラーが出ていたので、consoleに注目していればすぐ気づいたかもしれないが、
consoleを見る習慣がなかったのですぐに気づけなかった。

header.js:87 Failed to execute 'write' on 'Document': It isn't possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened.
header.js:87「ドキュメント」で「書き込み」を実行できませんでした:明示的に開かない限り、非同期にロードされた外部スクリプトからドキュメントに書き込むことはできません。

参考

scriptタグに async / defer を付けた場合のタイミング

12
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
12
Help us understand the problem. What is going on with this article?