任意のhtmlの非同期読み込み

ページの読み込み時間を考慮する最近のGoogleの取り組みに関連して、メインの最小値が読み込まれた後、Webページの一部を非同期に読み込むことがますます重要になっています。 広告は遅延ダウンロードの候補の1つですが、単純なajaxはここでは役に立ちません。 一般的なケースでは、例えば、document.writeはロードされたピースにあり、ドキュメントが既にロードされて閉じられている場合、このメソッドはそれを再び開き、ゼロにリセットします。



この点でGoogleはあまり役に立ちません、なぜなら 説明されている主なメソッドは、document.writeを独自のメソッドに置き換えることです。これにより、愚かにも引数がドキュメントの最後に追加されますが、呼び出しが最後に行かず、途中に書き込む必要がある場合-問題があります。 Fullajax フレームワークはハブで 説明されましたが、これに対処しているようですが、正確には-まだ見ていません。



私は別のアイデア、おそらく自転車を考えていましたが、試してみたいという衝動は強すぎました。 つまり、保留中のコードを非表示のiframeにロードし、ロード後にそのコンテンツをあるべき場所に転送します。 さらに、サーバーに不要な要求を行わないために、 データURIが使用されます。 このアプローチはFFおよびOperaで機能しますが、IEおよびChromeでは機能しません。



IEの問題は、8番目のバージョンまでデータURIをまったくサポートしていないことです。8番目では、この方法で画像とスタイルのみをエンコードできますが、htmlはエンコードできません。 Chromeのセキュリティ問題は、別のドメインからロードされていると仮定して、データURIを持つフレームのコンテンツを読み取れないことです。 iframeを埋め込むのではなく、サーバーから確実にロードすることはすべてのブラウザーで機能しますが、まだテストしていません。



もちろん、DOMチャンクはフレーム間でコピーできません。 一部のブラウザーにはdocument.importNodeメソッドがありますが、 Anthony Holdenerが書いているように 、イベントハンドラーをコピーしないため、常に手動でコピーするのが最善です。 さらに、document.writeを含むスクリプトの一部もコピーされます。これにより、愚かなコピーのinnerHTMLと同様にページもクリアされるため、とにかく手動でコピーする必要があります。



しかし、スクリプトを切り取った場合-スクリプトが既に機能していて、その作業の結果としてDOMをコピーできるのに、なぜ必要なのでしょうか? -イベントハンドラで使用されるメソッドとグローバル変数が失われる可能性があります。 解決策として、メインウィンドウにないiframeからすべてのウィンドウプロパティをコピーします。 おそらく同時に閉鎖に問題があるだろう、チェックしませんでした。 プロパティの一部を読み取ろうとすると例外が発生するため、コピーブロックをtry / catchでラップする必要があります。



読み込まれたhtmlコードにはCSSが含まれている可能性があるため、スタイルが残っています。 私は正直にこれを正しく行う方法を見つけられず、すべてのクラスと明示的に指定されたプロパティを計算した後の要素の最終スタイルを含むwindow.getComputedStyleメソッドを使用しました(クロスブラウザではないため、IEで異なる方法で実行する必要があります) 。 DOM階層をコピーするとき、htmlコードがロードされる非表示のフレームでそれらを見て、作成される要素を明示的に規定します。 しかし、すべてをコピーすることもオプションではないため、プロパティの「ホワイトリスト」を作成し、同様にtry / catchでラップする必要がありました。



そのため、遅延読み込みの場合は、ページの最後で登録する必要があります。



<iframe style='display:none' onLoad='l("...",this)' src='data:text/html;base64,...'></iframe>







ここで、最初の省略記号はコードをロードする必要がある要素のIDであり、2番目はbase64でエンコードされたコード自体です。 当然、そのようなiframeはいつでも動的に作成できます。たとえば、準備完了イベントやロードイベントを使用できます。 ブートローダーは次のようになります。







  1. var allowedStyles = {
  2. 色:
  3. カーソル: true
  4. backgroundColor: true
  5. backgroundImage: true
  6. borderTopWidth: true
  7. borderRightWidth: true
  8. borderBottomWidth: true
  9. borderLeftWidth: true
  10. ディスプレイ: true
  11. fontFamily: true
  12. fontSize: true
  13. fontSizeAdjust: true
  14. fontStretch: true
  15. fontStyle: true
  16. fontVariant: true
  17. fontWeight: true
  18. paddingTop: true
  19. paddingRight: true
  20. paddingBottom: true
  21. paddingLeft: true
  22. textAlign: true
  23. textDecoration: true
  24. };
  25. 関数 im(node、rec、w2){
  26. スイッチ (node.nodeType){
  27. ケース 文書 .ELEMENT_NODE:
  28. if (node.nodeName == 'SCRIPT'return false ;
  29. if (node.nodeName == 'IFRAME'return document .importNode(node、 true );
  30. var newNode = document .createElement(node.nodeName);
  31. //ノードには追加する属性がありますか?
  32. if (node.attributes && node.attributes.length> 0)
  33. forvar i = 0、il = node.attributes.length; i <il; i ++){
  34. var attrName = node.attributes [i] .nodeName;
  35. newNode.setAttribute(attrName、node.getAttribute(attrName));
  36. }
  37. //私たちも子供を追いかけていますか、ノードには何かありますか?
  38. if (rec && node.childNodes && node.childNodes.length> 0)
  39. forvar i = 0、il = node.childNodes.length; i <il; i ++){
  40. var newChild = im(node.childNodes [i]、rec、w2);
  41. if (newChild)newNode.appendChild(newChild);
  42. }
  43. //
  44. var styles = w2.getComputedStyle(node、 null );
  45. forvar s in styles) try {
  46. if (allowedStyles [s])newNode.style [s] =スタイル[s];
  47. } catch (e){}
  48. return newNode;
  49. ケース ドキュメント .TEXT_NODE:
  50. ケース ドキュメント .CDATA_SECTION_NODE:
  51. return document .createTextNode(node.nodeValue);
  52. }
  53. };
  54. 関数 l(名前、iframe){
  55. for (iframe.contentWindowのvar i)
  56. {
  57. if (window [i] === undefined)
  58. window [i] = iframe.contentWindow [i];
  59. } catch (e){}
  60. var d = document .getElementById(name);
  61. var children = iframe.contentDocument.body.childNodes;
  62. forvar i = 0、l = children.length; i <l; i ++){
  63. var clone = im(children [i]、 true 、iframe.contentWindow);
  64. if (クローン)d.appendChild(クローン);
  65. }
  66. }
*このソースコードは、 ソースコードハイライターで強調表示されました。




私がすでに書いたように、このアプローチは現時点では非常に機能しています。FFとOperaでのみ機能し、非常に粗雑ですが、先に進む前にアイデアをすばやく共有し、賢い人のコメントを読みたいと思いました。 解決されていない問題の1つは、ロードされたコードにiframeも含まれている場合の対処方法です。 広告の場合、これは珍しいことではありません。 これで、iframe要素はsrcとともにコピーされますが、フレームのコンテンツは再ロードされ、フレームが2回ロードされることがわかります。 DOMを介してそのコンテンツをコピーするか、innerHTMLを取得し、base64をエンコードしてsrc = "data:..."に書き込みます。オプションではありません。 iframeは別のドメインから読み込むことができ、ブラウザはセキュリティ上の理由からそのコンテンツへのアクセスを許可しません。 したがって、iframeを含むコードは、この方法でロードしない方が適切です。



All Articles