前回投稿した『jsdo.itでアクセスの多かったUIデザインに役立つJavaScriptコード紹介』という記事では、jsdo.itというサービスのウィジェットを15個表示させることにしました。ウィジェットはJavaScriptのdocument.write()が使われていたため、15個も表示させるとページがこれでもかというくらい重くなり、投稿も半ば諦めモードになりかけました。最終的にはdocument.write()が書き出すiframeを取り出し、遅延ロードさせるという方法でなんとか乗り切りました。その辺の話を詳しく書こうと思います。
目次
jsdo.it上のコードをページに埋め込む
jsdo.it内で書いたコードは、ウィジェットとしてブログなど好きなページに埋め込むことができるようになっています。jsdo.itのそれぞれのページに設置してある「ブログに埋め込む」というボタンを押すと、ページに埋め込むためのscriptタグがコピーできるようになっています。
コピーできるscriptタグは以下のようになっています。
上記のscriptタグをページに貼り付けると以下のようにjsdo.itのコードが表示されるようになっています。
コードを15個埋め込むとさすがに重い…
上記のように簡単にjsdo.itのコードをページ内に埋め込むことができるので、手軽にコードの紹介もできると思ったのが誤りでした…。何を欲張ったのかこのjsdo.itのコードを15個表示させることにしました。
記事を書くためにせっせとウィジェットを15個コピーしてはページに埋め込んでいきました。そうして気づいた時にはすでに時遅し、ページが激重になっていました…。プレビューもままならず、途方に暮れることになりました。せっかく記事も書いたし、投稿を辞めるわけにもいかず、いろいろ悩んだ挙句とにかくこの問題を解決させる道を模索することにしました。
ページが激重の原因はdocument.write()
まずscriptタグで読み込んでいるjsファイルがどうなっているか見てみることにしました。以下のscriptタグ内のsrc属性の値の部分(jsファイルのURL)をコピーしてブラウザのアドレスバーに貼り付けました。
展開されたjsファイルの中身は以下のようになっていました。
おわかりのように、激重の原因はdocument.write()でした。document.write()の問題点と言えば、document.write()による書き出しが終わるまで、それ以降のページのレンダリングを止めてしまうことです。それに拍車をかけるように、ウィジェット内には激重の代表格と言われているFacebookやTwitterのソーシャルボタンが使われていました。15個のウィジェットの表示が終わるまで、ページの読み込みが終わらないという最悪の状態となっていました。
docment.write()は非同期処理ができない
これを解決するために、まず考えたのはscrpt要素にasync属性やdefer属性をつけて非同期でウィジェットを表示させることでした。ただdocment.write()がくせものたる所以はここにあって、docment.write()はasync属性やdefer属性に対応していないということです。
要するに、実行された場所で即座に内容の生成を行うdocment.writeに対して、非同期系の処理を与えるということは無理があるということです。ということでウィジェットの非同期での表示は諦めざるをえませんでした。
ただ調べてみると以下のようにdocument.write()を非同期で実行させるような裏技的な方法は存在するようです。ただ自分はブログの記事に対して実装するのは面倒くさいと思って別の方法を探すことにしました。
- document.write()の実行タイミングをずらす方法 – ppBlog official
- JavaScript – Shift_JISなdocument.writeを非同期で実行する – Qiita
- タグマネージャによる高速化(document.write 非同期実行?) TECHSCORE BLOG
- document.writeを使った遅いブログパーツ(例えばzenback)を非同期化してサイトを高速表示する方法 – ゆっくりと…
iframe要素の遅延ロードを試すことに
ということで次に考えたのは、document.write()で書き出されるHTMLタグの部分を直接ブログの記事内に貼り付けることでした。上記でも触れたように、jsdo.itのscript要素のsrc属性に指定されているJSファイルを開くと以下のようになっています。
document.write()内のHTMLタグ部分を抜き出して、整形し直すと以下のようになります。これをそのままページに貼り付けることにしました。
ただ、これだけではdocument.write()とやっていることは変わらず、相変わらず激重なままです。そこで考えたのが、iframe要素の遅延ロードです。これしか方法はないかなと思いました。
遅延ロードの実装は、手っ取り早くjQueryプラグインに頼ることにしました。遅延ロードと言ったら、まず真っ先に思いつくのは、定番中の定番となっているlazyloadだと思います。
lazyloadはよく画像の遅延ロードに使われていますね。調べてみるとiframeにも対応しているようでした。ただ以下のブログを見るとiframeの対応はなんだか手間がかかりそうな感じがしたので、これも諦めて違うプラグインを探すことにしました。
iframe要素の遅延ロードの実装にはlayzr.jsが使えそう
そして見つけたのがlayzr.jsというJavaScriptのライブラリです。
軽量で、高速で、モダンで、jQueryなど何にも依存しないJSライブラリとなります。以下のブログ記事を見ると、すごく簡単にiframeの遅延ロードを実装できることがわかりました。
さっそくlayzr.jsを使ってiframeの遅延ロードを実装することにしました。
layzr.jsの実装方法
layzr.jsのダウンロード
まずlayzr.jsを以下のGitHubのページよりダウンロードします(npmやbowerにも対応しています)。またはGitHubのページに記載のCDNのURLをコピーします。
layzr.jsの読み込み
ダウンロードしたlayzr.jsをページに読み込みます。
iframeのsrc属性をdata-layzr属性に変更
iframeのsrc属性をdata-layzr属性に変更します。
新しいインスタンスを生成する
以下のコードを記載し、ページ読み込み後に、Layzrオブジェクトの新しいインスタンスを生成するようにします。
ローディング画像を設定する
これで遅延ロードされるようになりましたが、ロードされるまで空白が表示された状態となっているので、ローディング画像を設定しておきます。iframeのsrc属性にローディング画像を設定することができます。
ローディング画像は以下のサイトのものを使わせてもらいました。
iframe要素のレスポンシブ対応
忘れてはいけないのが、iframeのスマホ対応です。画面サイズに合わせてiframeのサイズをフレキシブルに変更する必要があります。今回はcssを使ってスマホ対応しました。書いたcssのコードは以下のようになります。
iframeのスマホ対応についての詳細は、当ブログの以下の記事を参考にしてください。
iframe要素の遅延ロードの実装完了
実装後のjsdo.itのウィジェットは以下のように遅延して表示されるようになりました。
layzr.jsは複数のiframeにも対応しています。上記で紹介した方法でインスタンスをひとつ生成するだけで、複数のiframeを遅延ロードさせることができるようになります。複数のiframeに遅延ロードを実装した例は当ブログの前回の記事になりますので、ぜひご確認ください。15個のウィジェットを表示させていますが、それほどもっさり感は感じないと思います。
まとめ
フロントエンドに力を入れている面白法人カヤックのサービスらしからぬ重々なウィジェットにかなり面食らいましたが、なんとか上記のような実装を施し、記事を公開することができました。ひとまずほっとしています。
今回利用したlayzr.js、なかなか使えると思います。今回はiframeの遅延ロード方法を紹介しましたが、もちろん画像にも使えます。オプションもいろいろ用意されているようなので、その辺りも今後詳しく見ていこうと思っています。世の中には激重なウィジェットがたくさん存在していると思います。こういった解決策もあるものだと参考にしてもらえれば幸いです。
コメント