การนำเข้า HTML

รวมสำหรับเว็บ

เหตุผลที่ควรนําเข้า

ลองนึกถึงวิธีที่คุณโหลดทรัพยากรประเภทต่างๆ บนเว็บ สำหรับ JS เรามี <script src> สําหรับ CSS ตัวเลือกที่เหมาะสําหรับคุณน่าจะเป็น <link rel="stylesheet"> สำหรับรูปภาพจะเป็น <img> วิดีโอมี <video> เสียง <audio>… เข้าประเด็นเลย เนื้อหาส่วนใหญ่ของเว็บมีวิธีโหลดตัวเองที่ง่ายและชัดเจน แต่ไม่ใช่สำหรับ HTML ตัวเลือกของคุณมีดังนี้

  1. <iframe> - ได้ผลดีแต่มีน้ำหนักมาก เนื้อหาของ iframe จะอยู่ในบริบทที่แยกจากหน้าเว็บของคุณโดยสิ้นเชิง แม้ว่าฟีเจอร์นี้จะยอดเยี่ยม แต่ก็ยังทำให้เกิดปัญหาเพิ่มเติม (การปรับขนาดเฟรมให้พอดีกับเนื้อหานั้นทำได้ยากมาก เขียนสคริปต์เข้า/ออกจากเฟรมได้ยากมาก และแทบจะจัดสไตล์ไม่ได้)
  2. AJAX - ฉันชอบ xhr.responseType="document" แต่คุณบอกว่าฉันต้องใช้ JS เพื่อโหลด HTML ไม่น่าเป็นไปได้
  3. CrazyHacks™ - ฝังอยู่ในสตริง ซ่อนอยู่ในรูปแบบความคิดเห็น (เช่น <script type="text/html">) น่าขยะแขยง

เข้าใจความย้อนแย้งไหม เนื้อหาพื้นฐานที่สุดของเว็บอย่าง HTML ต้องใช้ความพยายามมากที่สุดในการดำเนินการ แต่โชคดีที่เรามีคอมโพเนนต์ของเว็บที่จะช่วยเรากลับมาทำงานได้ตามปกติ

เริ่มต้นใช้งาน

การนําเข้า HTML ซึ่งเป็นส่วนหนึ่งของการแคสต์ Web Components เป็นวิธีรวมเอกสาร HTML ไว้ในเอกสาร HTML อื่นๆ นอกจากนี้ คุณยังใช้มาร์กอัปได้อีกด้วย การนำเข้ายังรวม CSS, JavaScript หรือทุกอย่างที่มีในไฟล์ .html ได้ด้วย กล่าวคือ การดำเนินการนี้ทำให้การนําเข้าเป็นเครื่องมือที่ยอดเยี่ยมสําหรับการโหลด HTML/CSS/JS ที่เกี่ยวข้อง

ข้อมูลพื้นฐาน

รวมการนําเข้าในหน้าเว็บของคุณโดยการประกาศ <link rel="import">:

<head>
    <link rel="import" href="/path/to/imports/stuff.html">
</head>

URL ของการนำเข้าจะเรียกว่าตำแหน่งการนำเข้า หากต้องการโหลดเนื้อหาจากโดเมนอื่น ตำแหน่งการนําเข้าต้องเปิดใช้ CORS โดยทำดังนี้

<!-- Resources on other origins must be CORS-enabled. -->
<link rel="import" href="http://example.com/elements.html">

การตรวจหาและรองรับฟีเจอร์

หากต้องการตรวจหาการสนับสนุน ให้ตรวจสอบว่ามี .import อยู่ในองค์ประกอบ <link> หรือไม่

function supportsImports() {
    return 'import' in document.createElement('link');
}

if (supportsImports()) {
    // Good to go!
} else {
    // Use other libraries/require systems to load files.
}

การรองรับเบราว์เซอร์ยังอยู่ในขั้นเริ่มต้น Chrome 31 เป็นเบราว์เซอร์แรกที่ได้เห็นการใช้งาน แต่ผู้ให้บริการเบราว์เซอร์รายอื่นกำลังรอดูว่าโมดูล ES จะทำงานอย่างไร อย่างไรก็ตาม Polyfill ของ webcomponents.js จะใช้งานได้ดีในเบราว์เซอร์อื่นๆ จนกว่าจะมีการใช้งานอย่างแพร่หลาย

การรวมทรัพยากร

การนำเข้าเป็นระบบในการรวม HTML/CSS/JS (รวมถึงการนำเข้า HTML อื่นๆ) ไว้ในการส่งเดียว ฟีเจอร์นี้เป็นฟีเจอร์พื้นฐานที่มีประสิทธิภาพ หากคุณกำลังสร้างธีม ไลบรารี หรือเพียงแค่ต้องการแบ่งแอปออกเป็นส่วนๆ ตามความเหมาะสม การให้ URL เดียวแก่ผู้ใช้ก็เป็นสิ่งที่น่าสนใจ คุณยังส่งแอปทั้งแอปผ่านการนําเข้าได้ด้วย ลองคิดดูสิ

ตัวอย่างการใช้งานจริงคือ Bootstrap Bootstrap ประกอบด้วยไฟล์เดี่ยวๆ (bootstrap.css, bootstrap.js, แบบอักษร) ต้องใช้ JQuery สําหรับปลั๊กอิน และแสดงตัวอย่างมาร์กอัป นักพัฒนาแอปชอบความยืดหยุ่นแบบเลือกได้ตามต้องการ ซึ่งช่วยให้องค์กรซื้อส่วนต่างๆ ของเฟรมเวิร์กที่ต้องการใช้ อย่างไรก็ตาม เราขอเดาว่านักพัฒนาซอฟต์แวร์ทั่วไปจะเลือกวิธีที่ง่ายและดาวน์โหลด Bootstrap ทั้งหมด

การนําเข้าเหมาะสําหรับสิ่งต่างๆ เช่น Bootstrap เรานำเสนออนาคตของการโหลด Bootstrap ต่อคุณ:

<head>
    <link rel="import" href="bootstrap.html">
</head>

ผู้ใช้เพียงโหลดลิงก์การนําเข้า HTML ผู้ใช้ไม่จำเป็นต้องกังวลกับไฟล์ที่กระจัดกระจาย แต่ระบบจะจัดการและรวม Bootstrap ทั้งหมดไว้ในไฟล์ bootstrap.html ที่จะนําเข้า

<link rel="stylesheet" href="bootstrap.css">
<link rel="stylesheet" href="fonts.css">
<script src="jquery.js"></script>
<script src="bootstrap.js"></script>
<script src="bootstrap-tooltip.js"></script>
<script src="bootstrap-dropdown.js"></script>
...

<!-- scaffolding markup -->
<template>
    ...
</template>

ปล่อยให้นั่งรอ เป็นเรื่องที่น่าตื่นเต้น

เหตุการณ์การโหลด/ข้อผิดพลาด

องค์ประกอบ <link> จะเรียกเหตุการณ์ load เมื่อการนําเข้าโหลดสําเร็จ และ onerror เมื่อการพยายามนําเข้าล้มเหลว (เช่น ทรัพยากรแสดงผลเป็น 404)

การนําเข้าจะพยายามโหลดทันที วิธีง่ายๆ ในการหลีกเลี่ยงความยุ่งยากคือการใช้สําหรับแอตทริบิวต์ onload/onerror

<script>
    function handleLoad(e) {
    console.log('Loaded import: ' + e.target.href);
    }
    function handleError(e) {
    console.log('Error loading import: ' + e.target.href);
    }
</script>

<link rel="import" href="file.html"
        onload="handleLoad(event)" onerror="handleError(event)">

หรือหากจะสร้างการนําเข้าแบบไดนามิก ให้ทําดังนี้

var link = document.createElement('link');
link.rel = 'import';
// link.setAttribute('async', ''); // make it async!
link.href = 'file.html';
link.onload = function(e) {...};
link.onerror = function(e) {...};
document.head.appendChild(link);

การใช้เนื้อหา

การรวมการนําเข้าในหน้าเว็บไม่ได้หมายความว่า "วางเนื้อหาของไฟล์นั้นที่นี่" โดยแปลว่า "โปรแกรมแยกวิเคราะห์ โปรดไปดึงข้อมูลเอกสารนี้เพื่อที่จะได้ใช้งาน" ในการใช้งานเนื้อหา คุณต้องลงมือทำและเขียนสคริปต์

aha! ช่วงเวลาสําคัญคือการตระหนักว่าการนําเข้าเป็นเพียงเอกสาร ที่จริงแล้ว เนื้อหาของการนำเข้าเรียกว่าเอกสารนำเข้า คุณสามารถจัดการข้อมูลการนําเข้าโดยใช้ DOM API มาตรฐาน

link.import

หากต้องการเข้าถึงเนื้อหาของการนําเข้า ให้ใช้พร็อพเพอร์ตี้ .import ขององค์ประกอบลิงก์ ดังนี้

var content = document.querySelector('link[rel="import"]').import;

link.import คือ null ภายใต้เงื่อนไขต่อไปนี้

  • เบราว์เซอร์ไม่รองรับการนำเข้า HTML
  • <link> ไม่มี rel="import"
  • ยังไม่ได้เพิ่ม <link> ลงใน DOM
  • ระบบนำ <link> ออกจาก DOM แล้ว
  • ทรัพยากรไม่ได้เปิดใช้ CORS

ตัวอย่างแบบเต็ม

สมมติว่า warnings.html มี:

<div class="warning">
    <style>
    h3 {
        color: red !important;
    }
    </style>
    <h3>Warning!
    <p>This page is under construction
</div>

<div class="outdated">
    <h3>Heads up!
    <p>This content may be out of date
</div>

ผู้นำเข้าสามารถคัดลอกส่วนที่ต้องการของเอกสารนี้ไปวางในหน้าเว็บของตนได้

<head>
    <link rel="import" href="warnings.html">
</head>
<body>
    ...
    <script>
    var link = document.querySelector('link[rel="import"]');
    var content = link.import;

    // Grab DOM from warning.html's document.
    var el = content.querySelector('.warning');

    document.body.appendChild(el.cloneNode(true));
    </script>
</body>

สคริปต์ในการนําเข้า

การนําเข้าไม่ได้อยู่ในเอกสารหลัก พวกเขารับบทดาวเทียมมา อย่างไรก็ตาม การนำเข้าของคุณยังสามารถดำเนินการกับหน้าหลักได้ แม้ว่าเอกสารหลักจะมีความสำคัญสูงสุดก็ตาม การนําเข้าสามารถเข้าถึง DOM ของตนเองและ/หรือ DOM ของหน้าเว็บที่นําเข้าได้ ดังนี้

ตัวอย่าง - purchase.html ที่เพิ่มสไตล์ชีตหนึ่งลงในหน้าหลัก

<link rel="stylesheet" href="http://www.example.com/styles.css">
<link rel="stylesheet" href="http://www.example.com/styles2.css">

<style>
/* Note: <style> in an import apply to the main
    document by default. That is, style tags don't need to be
    explicitly added to the main document. */
#somecontainer {
color: blue;
}
</style>
...

<script>
// importDoc references this import's document
var importDoc = document.currentScript.ownerDocument;

// mainDoc references the main document (the page that's importing us)
var mainDoc = document;

// Grab the first stylesheet from this import, clone it,
// and append it to the importing document.
    var styles = importDoc.querySelector('link[rel="stylesheet"]');
    mainDoc.head.appendChild(styles.cloneNode(true));
</script>

สังเกตสิ่งที่เกิดขึ้น สคริปต์ภายในการนําเข้าจะอ้างอิงเอกสารที่นําเข้า (document.currentScript.ownerDocument) และเพิ่มส่วนหนึ่งของเอกสารนั้นต่อท้ายหน้าการนําเข้า (mainDoc.head.appendChild(...)) ค่อนข้างซับซ้อน

กฎของ JavaScript ในการนําเข้า

  • สคริปต์ในการนําเข้าจะทํางานในบริบทของหน้าต่างที่มีdocumentที่นําเข้า ดังนั้น window.document จึงหมายถึงเอกสารหน้าหลัก ผลที่ตามมาที่เป็นประโยชน์ 2 ประการ ได้แก่
    • ฟังก์ชันที่กําหนดในการนําเข้าจะปรากฏใน window
    • คุณไม่ต้องทำอะไรยาก เช่น เพิ่มบล็อก <script> ของการนำเข้าลงในหน้าหลัก สคริปต์จะทำงานอีกครั้ง
  • การนําเข้าจะไม่บล็อกการแยกวิเคราะห์หน้าหลัก อย่างไรก็ตาม ระบบจะประมวลผลสคริปต์ภายในตามลําดับ ซึ่งหมายความว่าคุณจะได้รับลักษณะการทำงานแบบเลื่อนเวลาไว้ขณะที่รักษาลําดับสคริปต์ที่เหมาะสม ดูข้อมูลเพิ่มเติมด้านล่าง

การนำส่งคอมโพเนนต์เว็บ

การออกแบบการนําเข้า HTML เหมาะสําหรับการโหลดเนื้อหาที่นํามาใช้ซ้ำบนเว็บ ซึ่งเป็นวิธีที่เหมาะสมในการเผยแพร่คอมโพเนนต์ของเว็บ ทุกอย่างตั้งแต่ HTML <template> พื้นฐานไปจนถึงองค์ประกอบที่กำหนดเองอย่างเต็มรูปแบบที่มี Shadow DOM [1, 2, 3] เมื่อใช้เทคโนโลยีเหล่านี้ร่วมกัน การนําเข้าจะกลายเป็น #include สําหรับคอมโพเนนต์ของเว็บ

รวมเทมเพลต

องค์ประกอบเทมเพลต HTML เหมาะสมกับการนำเข้า HTML <template> เหมาะอย่างยิ่งสำหรับการสร้างโครงสร้างส่วนต่างๆ ของมาร์กอัปเพื่อให้แอปที่นำเข้านำไปใช้ได้ตามต้องการ การรวมเนื้อหาใน <template> ยังให้คุณได้รับประโยชน์เพิ่มเติมในการทำให้เนื้อหาไม่มีผลจนกว่าจะใช้งาน กล่าวคือ สคริปต์จะไม่ทํางานจนกว่าจะเพิ่มเทมเพลตลงใน DOM) ตูม

import.html

<template>
    <h1>Hello World!</h1>
    <!-- Img is not requested until the <template> goes live. -->
    <img src="world.png">
    <script>alert("Executed when the template is activated.");</script>
</template>
index.html

<head>
    <link rel="import" href="import.html">
</head>
<body>
    <div id="container"></div>
    <script>
    var link = document.querySelector('link[rel="import"]');

    // Clone the <template> in the import.
    var template = link.import.querySelector('template');
    var clone = document.importNode(template.content, true);

    document.querySelector('#container').appendChild(clone);
    </script>
</body>

การลงทะเบียนองค์ประกอบที่กำหนดเอง

องค์ประกอบที่กำหนดเองเป็นเทคโนโลยี Web Components อีกอย่างหนึ่งที่ทำงานร่วมกับ HTML Imports ได้อย่างยอดเยี่ยม การนําเข้าสามารถเรียกใช้สคริปต์ได้ ดังนั้นคุณควรกําหนด + ลงทะเบียนองค์ประกอบที่กําหนดเองเพื่อไม่ให้ผู้ใช้ต้องดำเนินการ เราเรียกกระบวนการนี้ว่า "การลงทะเบียนอัตโนมัติ"

elements.html

<script>
    // Define and register <say-hi>.
    var proto = Object.create(HTMLElement.prototype);

    proto.createdCallback = function() {
    this.innerHTML = 'Hello, <b>' +
                        (this.getAttribute('name') || '?') + '</b>';
    };

    document.registerElement('say-hi', {prototype: proto});
</script>

<template id="t">
    <style>
    ::content > * {
        color: red;
    }
    </style>
    <span>I'm a shadow-element using Shadow DOM!</span>
    <content></content>
</template>

<script>
    (function() {
    var importDoc = document.currentScript.ownerDocument; // importee

    // Define and register <shadow-element>
    // that uses Shadow DOM and a template.
    var proto2 = Object.create(HTMLElement.prototype);

    proto2.createdCallback = function() {
        // get template in import
        var template = importDoc.querySelector('#t');

        // import template into
        var clone = document.importNode(template.content, true);

        var root = this.createShadowRoot();
        root.appendChild(clone);
    };

    document.registerElement('shadow-element', {prototype: proto2});
    })();
</script>

การนําเข้านี้จะกําหนด (และลงทะเบียน) องค์ประกอบ 2 รายการ ได้แก่ <say-hi> และ <shadow-element> รายการแรกแสดงองค์ประกอบที่กำหนดเองพื้นฐานที่ลงทะเบียนตัวเองภายในการนําเข้า ตัวอย่างที่ 2 แสดงวิธีใช้องค์ประกอบที่กําหนดเองซึ่งสร้าง Shadow DOM จาก <template> จากนั้นลงทะเบียนตัวเอง

สิ่งที่ยอดเยี่ยมที่สุดเกี่ยวกับการลงทะเบียนองค์ประกอบที่กำหนดเองภายในการนําเข้า HTML คือผู้นําเข้าเพียงต้องประกาศองค์ประกอบของคุณในหน้าเว็บ ไม่จำเป็นต้องต่อสายไฟ

index.html

<head>
    <link rel="import" href="elements.html">
</head>
<body>
    <say-hi name="Eric"></say-hi>
    <shadow-element>
    <div>( I'm in the light dom )</div>
    </shadow-element>
</body>

ในความคิดของผม การใช้เวิร์กโฟลว์นี้เพียงอย่างเดียวก็ทำให้การนำเข้า HTML เป็นวิธีการที่เหมาะสมในการแชร์คอมโพเนนต์ของเว็บ

การจัดการทรัพยากร Dependency และการนําเข้าย่อย

การนําเข้าย่อย

ซึ่งอาจมีประโยชน์สำหรับการนําเข้ารายการหนึ่งเพื่อรวมรายการอื่น เช่น หากต้องการนําคอมโพเนนต์อื่นมาใช้ซ้ำหรือขยาย ให้ใช้การนําเข้าเพื่อโหลดองค์ประกอบอื่นๆ

ด้านล่างนี้เป็นตัวอย่างจริงจาก Polymer คอมโพเนนต์นี้เป็นคอมโพเนนต์แท็บใหม่ (<paper-tabs>) ที่ใช้เลย์เอาต์และคอมโพเนนต์ตัวเลือกซ้ำ จัดการทรัพยากร Dependency โดยใช้การนําเข้า HTML

paper-tabs.html (แบบง่าย)

<link rel="import" href="iron-selector.html">
<link rel="import" href="classes/iron-flex-layout.html">

<dom-module id="paper-tabs">
    <template>
    <style>...</style>
    <iron-selector class="layout horizonta center">
        <content select="*"></content>
    </iron-selector>
    </template>
    <script>...</script>
</dom-module>

นักพัฒนาแอปจะนำเข้าองค์ประกอบใหม่นี้ได้โดยใช้สิ่งต่อไปนี้

<link rel="import" href="paper-tabs.html">
<paper-tabs></paper-tabs>

เมื่อ <iron-selector2> ใหม่และเจ๋งกว่าเดิมเปิดตัวในอนาคต คุณสามารถเปลี่ยน <iron-selector> และเริ่มใช้งานได้ทันที คุณจะไม่ต้องทำให้ผู้ใช้เสียประสบการณ์การใช้งานด้วยฟีเจอร์การนําเข้าและคอมโพเนนต์เว็บ

การจัดการการขึ้นต่อกัน

เราทุกคนทราบดีว่าการโหลด JQuery มากกว่า 1 ครั้งต่อหน้าเว็บทำให้เกิดข้อผิดพลาด การดำเนินการนี้จะไม่ก่อให้เกิดปัญหาใหญ่สำหรับคอมโพเนนต์เว็บเมื่อคอมโพเนนต์หลายรายการใช้ไลบรารีเดียวกันใช่ไหม ก็จะไม่ถ้าเราใช้การนำเข้า HTML! ซึ่งสามารถใช้เพื่อจัดการการพึ่งพาได้

การรวมไลบรารีในการนําเข้า HTML จะเป็นการกรองทรัพยากรที่ซ้ำกันออกโดยอัตโนมัติ ระบบจะแยกวิเคราะห์เอกสารเพียงครั้งเดียว สคริปต์จะทำงานเพียงครั้งเดียว ตัวอย่างเช่น สมมติว่าคุณกำหนดการนำเข้า jquery.html ซึ่งโหลดสำเนาของ JQuery

jquery.html

<script src="http://cdn.com/jquery.js"></script>

คุณสามารถนําการนําเข้านี้มาใช้ซ้ำในการนําเข้าครั้งต่อๆ ไป ดังนี้

import2.html

<link rel="import" href="jquery.html">
<div>Hello, I'm import 2</div>
ajax-element.html

<link rel="import" href="jquery.html">
<link rel="import" href="import2.html">

<script>
    var proto = Object.create(HTMLElement.prototype);

    proto.makeRequest = function(url, done) {
    return $.ajax(url).done(function() {
        done();
    });
    };

    document.registerElement('ajax-element', {prototype: proto});
</script>

แม้แต่หน้าหลักเองก็สามารถมี jquery.html ได้หากต้องใช้ไลบรารีนี้

<head>
    <link rel="import" href="jquery.html">
    <link rel="import" href="ajax-element.html">
</head>
<body>

...

<script>
    $(document).ready(function() {
    var el = document.createElement('ajax-element');
    el.makeRequest('http://example.com');
    });
</script>
</body>

แม้ว่า jquery.html จะรวมอยู่ในต้นไม้การนําเข้าหลายรายการ แต่เบราว์เซอร์จะดึงข้อมูลและประมวลผลเอกสารเพียงครั้งเดียว การตรวจสอบแผงเครือข่ายยืนยันข้อมูลนี้

มีการขอ jquery.html 1 ครั้ง
มีการขอ jquery.html 1 ครั้ง

ข้อพิจารณาด้านประสิทธิภาพ

การนำเข้า HTML นั้นยอดเยี่ยมมาก แต่เช่นเดียวกับเทคโนโลยีเว็บใหม่ๆ คุณควรใช้งานอย่างชาญฉลาด แนวทางปฏิบัติแนะนำสำหรับการพัฒนาเว็บยังคงใช้ได้อยู่ สิ่งที่ควรคำนึงถึงมีดังนี้

นำเข้าแบบต่อท้าย

การลดคำขอเครือข่ายเป็นสิ่งสำคัญเสมอ หากคุณมีลิงก์การนําเข้าระดับบนสุดจํานวนมาก ให้ลองรวมลิงก์เหล่านั้นเป็นทรัพยากรเดียวแล้วนําเข้าไฟล์นั้น

Vulcanize คือเครื่องมือสร้าง npm จากทีม Polymer ซึ่งรวมชุดการนำเข้า HTML หลายๆ ชุดไว้ในไฟล์เดียว ขั้นตอนนี้เปรียบเสมือนขั้นตอนการสร้างการต่อเชื่อมสําหรับคอมโพเนนต์เว็บ

การนำเข้าใช้ประโยชน์จากการแคชเบราว์เซอร์

หลายคนลืมไปว่าแพ็กเกจการทํางานของเครือข่ายเบราว์เซอร์ได้รับการปรับแต่งมาอย่างละเอียดตลอดหลายปีที่ผ่านมา การนําเข้า (และการนําเข้าย่อย) ใช้ประโยชน์จากตรรกะนี้ด้วย การนําเข้า http://cdn.com/bootstrap.html อาจมีทรัพยากรย่อย แต่ระบบจะแคชไว้

เนื้อหาจะมีประโยชน์ก็ต่อเมื่อคุณเพิ่มเนื้อหานั้นเท่านั้น

โปรดทราบว่าเนื้อหาจะทำงานไม่ได้จนกว่าคุณจะเรียกใช้บริการ มาดูตัวอย่างสไตล์ชีตปกติที่สร้างขึ้นแบบไดนามิกกัน

var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'styles.css';

เบราว์เซอร์จะไม่ขอ styles.css จนกว่าจะมีการเพิ่ม link ลงใน DOM

document.head.appendChild(link); // browser requests styles.css

อีกตัวอย่างหนึ่งคือมาร์กอัปที่สร้างขึ้นแบบไดนามิก

var h2 = document.createElement('h2');
h2.textContent = 'Booyah!';

h2 จะไม่มีความหมายจนกว่าคุณจะเพิ่มลงใน DOM

แนวคิดเดียวกันนี้ใช้กับเอกสารที่นำเข้าได้ เว้นแต่คุณจะเพิ่มเนื้อหาของไฟล์ต่อท้าย DOM การดำเนินการนี้จะใช้งานไม่ได้ ความจริงแล้ว <script> เป็นเพียงสิ่งเดียวที่ "ทำงาน" ในเอกสารการนําเข้าโดยตรง ดูการเขียนสคริปต์ในการนำเข้า

การเพิ่มประสิทธิภาพสําหรับการโหลดแบบไม่ซิงค์

การนําเข้าบล็อกการแสดงผล

การนำเข้าบล็อกการแสดงผลของหน้าหลัก สิ่งนี้คล้ายกับสิ่งที่ <link rel="stylesheet"> ทำ เหตุผลที่เบราว์เซอร์บล็อกการแสดงผลในสไตล์ชีตในตอนแรกคือเพื่อลด FOUC การนำเข้าจะทำงานคล้ายกันเนื่องจากมีสไตไลซ์ได้

หากต้องการให้ไม่พร้อมกันโดยสมบูรณ์และไม่บล็อกโปรแกรมแยกวิเคราะห์หรือการแสดงภาพ ให้ใช้แอตทริบิวต์ async ดังนี้

<link rel="import" href="/path/to/import_that_takes_5secs.html" async>

async ไม่ได้เป็นค่าเริ่มต้นสำหรับการนําเข้า HTML เนื่องจากนักพัฒนาซอฟต์แวร์ต้องทํางานมากขึ้น การทำงานแบบซิงค์โดยค่าเริ่มต้นหมายความว่าการนําเข้า HTML ที่มีคําจํากัดความขององค์ประกอบที่กําหนดเองจะได้รับการรับประกันว่าจะโหลดและอัปเกรดตามลําดับ ในโลกแบบแอซิงค์ทั้งหมด นักพัฒนาแอปจะต้องจัดการการเต้นและเวลาอัปเกรดด้วยตนเอง

นอกจากนี้ คุณยังสร้างการนําเข้าแบบไม่พร้อมกันแบบไดนามิกได้ด้วย โดยทําดังนี้

var l = document.createElement('link');
l.rel = 'import';
l.href = 'elements.html';
l.setAttribute('async', '');
l.onload = function(e) { ... };

การนําเข้าจะไม่บล็อกการแยกวิเคราะห์

การนำเข้าจะไม่บล็อกการแยกวิเคราะห์หน้าหลัก ระบบจะประมวลผลสคริปต์ภายในการนำเข้าตามลำดับแต่ไม่บล็อกหน้าการนำเข้า ซึ่งหมายความว่าคุณจะได้รับลักษณะการทำงานแบบเลื่อนเวลาไว้ชั่วคราวขณะที่รักษาลําดับสคริปต์ที่เหมาะสม ข้อดีอย่างหนึ่งของการเพิ่มการนำเข้าใน <head> คือจะทำให้โปรแกรมแยกวิเคราะห์เริ่มทำงานในเนื้อหาได้โดยเร็วที่สุด อย่างไรก็ตาม สิ่งสำคัญก็คือคุณต้องจำ <script> ในเอกสารหลักว่ายังคงบล็อกหน้านั้นต่อไป <script> แรกหลังจากการนำเข้าจะบล็อกการแสดงผลหน้าเว็บ เนื่องจากการนําเข้าอาจมีสคริปต์อยู่ภายในที่ต้องเรียกใช้ก่อนสคริปต์ในหน้าหลัก

<head>
    <link rel="import" href="/path/to/import_that_takes_5secs.html">
    <script>console.log('I block page rendering');</script>
</head>

การเพิ่มประสิทธิภาพลักษณะการทำงานแบบแอซิงค์ทำได้หลายวิธี โดยขึ้นอยู่กับโครงสร้างแอปและกรณีการใช้งาน เทคนิคด้านล่างจะช่วยบรรเทาการบล็อกการแสดงผลหน้าหลัก

สถานการณ์ที่ 1 (แนะนำ): คุณไม่มีสคริปต์ใน <head> หรือในบรรทัดใน <body>

คําแนะนําของเราสําหรับการวาง <script> คือหลีกเลี่ยงการวางไว้ทันทีหลังจากการนําเข้า ย้ายสคริปต์ในช่วงท้ายเกมให้มากที่สุด แต่คุณก็ใช้แนวทางปฏิบัติแนะนำนี้อยู่แล้วใช่ไหม ;)

เช่น

<head>
    <link rel="import" href="/path/to/import.html">
    <link rel="import" href="/path/to/import2.html">
    <!-- avoid including script -->
</head>
<body>
    <!-- avoid including script -->

    <div id="container"></div>

    <!-- avoid including script -->
    ...

    <script>
    // Other scripts n' stuff.

    // Bring in the import content.
    var link = document.querySelector('link[rel="import"]');
    var post = link.import.querySelector('#blog-post');

    var container = document.querySelector('#container');
    container.appendChild(post.cloneNode(true));
    </script>
</body>

ทุกอย่างอยู่ที่ด้านล่าง

สถานการณ์ 1.5: การนำเข้าเพิ่มตัวเอง

อีกทางเลือกหนึ่งคือการนําเข้าเนื้อหาของตนเอง หากผู้เขียนการนําเข้าจัดทำสัญญาให้นักพัฒนาแอปปฏิบัติตาม การนําเข้าจะเพิ่มตัวเองไปยังพื้นที่ของหน้าหลักได้ ดังนี้

import.html:

<div id="blog-post">...</div>
<script>
    var me = document.currentScript.ownerDocument;
    var post = me.querySelector('#blog-post');

    var container = document.querySelector('#container');
    container.appendChild(post.cloneNode(true));
</script>
index.html

<head>
    <link rel="import" href="/path/to/import.html">
</head>
<body>
    <!-- no need for script. the import takes care of things -->
</body>

สถานการณ์ #2: คุณมีสคริปต์ใน <head> หรือแทรกใน <body>

หากคุณมีการนําเข้าที่ใช้เวลาโหลดนาน <script> รายการแรกที่ตามหลังมาจะบล็อกไม่ให้หน้าเว็บแสดงผล ตัวอย่างเช่น Google Analytics แนะนำให้วางโค้ดติดตามใน <head> หากคุณไม่สามารถหลีกเลี่ยงการวาง <script> ใน <head> การเพิ่มการนำเข้าแบบไดนามิกจะป้องกันไม่ให้หน้านี้บล็อกหน้า

<head>
    <script>
    function addImportLink(url) {
        var link = document.createElement('link');
        link.rel = 'import';
        link.href = url;
        link.onload = function(e) {
        var post = this.import.querySelector('#blog-post');

        var container = document.querySelector('#container');
        container.appendChild(post.cloneNode(true));
        };
        document.head.appendChild(link);
    }

    addImportLink('/path/to/import.html'); // Import is added early :)
    </script>
    <script>
    // other scripts
    </script>
</head>
<body>
    <div id="container"></div>
    ...
</body>

หรือเพิ่มการนำเข้าใกล้กับส่วนท้ายของ <body>:

<head>
    <script>
    // other scripts
    </script>
</head>
<body>
    <div id="container"></div>
    ...

    <script>
    function addImportLink(url) { ... }

    addImportLink('/path/to/import.html'); // Import is added very late :(
    </script>
</body>

สิ่งที่ต้องจดจำ

  • Mimetype ของการนําเข้าคือ text/html

  • ทรัพยากรจากต้นทางอื่นๆ ต้องเปิดใช้ CORS

  • การนำเข้าจาก URL เดียวกันจะถูกดึงและแยกวิเคราะห์เพียงครั้งเดียว ซึ่งหมายความว่าสคริปต์ในการนำเข้าจะทำงานเฉพาะครั้งแรกที่เห็นการนำเข้าเท่านั้น

  • สคริปต์ในการนำเข้าจะได้รับการประมวลผลตามลำดับ แต่ไม่บล็อกการแยกวิเคราะห์เอกสารหลัก

  • ลิงก์การนําเข้าไม่ได้หมายถึง "#include the content here" ซึ่งหมายความว่า "ไปดึงข้อมูลเอกสารนี้มาเพื่อให้ฉันใช้ภายหลัง" ในขณะที่สคริปต์ทำงานในขณะนำเข้า จะต้องเพิ่มสไตล์ชีต มาร์กอัป และทรัพยากรอื่นๆ ลงในหน้าหลักอย่างชัดเจน โปรดทราบว่าคุณไม่จำเป็นต้องเพิ่ม <style> อย่างชัดเจน ความแตกต่างที่สำคัญระหว่างการนําเข้า HTML กับ <iframe> คือ <iframe> จะระบุว่า "โหลดและแสดงผลเนื้อหานี้ที่นี่"

บทสรุป

การนําเข้า HTML ช่วยให้คุณสามารถรวม HTML/CSS/JS เป็นทรัพยากรรายการเดียวได้ แม้ว่าจะมีประโยชน์ในตัวเอง แต่ความคิดนี้ก็กลายเป็นสิ่งที่ทรงพลังอย่างยิ่งในโลกของ Web Components นักพัฒนาแอปสามารถสร้างคอมโพเนนต์ที่ใช้ซ้ำได้เพื่อให้คนอื่นๆ ใช้งานและนำเข้ามาในแอปของตน โดยทั้งหมดจะนำส่งผ่าน <link rel="import">

การนําเข้า HTML เป็นแนวคิดที่เรียบง่าย แต่เปิดโอกาสให้แพลตฟอร์มมีกรณีการใช้งานที่น่าสนใจหลายกรณี

กรณีการใช้งาน

  • เผยแพร่ HTML/CSS/JS ที่เกี่ยวข้องเป็นกลุ่มเดียว ตามหลักแล้ว คุณอาจนำเข้าเว็บแอปทั้งแอปไปยังเว็บแอปอื่นได้
  • การจัดระเบียบโค้ด - จัดแบ่งแนวคิดออกเป็นไฟล์ต่างๆ อย่างมีเหตุผล ซึ่งจะช่วยส่งเสริมความเป็นโมดูลและความสามารถในการนํากลับมาใช้ใหม่**
  • ส่งคําจํากัดความองค์ประกอบที่กําหนดเองอย่างน้อย 1 รายการ การนำเข้าสามารถใช้เพื่อregisterและรวมไว้ในแอป การดำเนินการนี้จะทำให้รูปแบบซอฟต์แวร์ที่ดี ทำให้อินเทอร์เฟซ/คำจำกัดความขององค์ประกอบแยกจากการใช้งาน
  • จัดการทรัพยากรที่เกี่ยวข้อง - ระบบจะกรองทรัพยากรที่ซ้ำกันออกโดยอัตโนมัติ
  • แยกสคริปต์เป็นกลุ่ม - ก่อนที่จะนําเข้า ไลบรารี JS ขนาดใหญ่จะต้องแยกวิเคราะห์ไฟล์ทั้งหมดเพื่อเริ่มทํางาน ซึ่งทําให้ช้า เมื่อนำเข้าแล้ว ไลบรารีจะเริ่มทํางานทันทีที่แยกวิเคราะห์ข้อมูลส่วน A เวลาในการตอบสนองน้อยลง
// TODO: DevSite - Code sample removed as it used inline event handlers
  • แยกวิเคราะห์ HTML แบบขนาน - เป็นครั้งแรกที่เบราว์เซอร์สามารถเรียกใช้โปรแกรมแยกวิเคราะห์ HTML 2 รายการ (หรือมากกว่า) พร้อมกัน

  • เปิดใช้การสลับระหว่างโหมดแก้ไขข้อบกพร่องและโหมดที่ไม่แก้ไขข้อบกพร่องในแอปได้ง่ายๆ เพียงเปลี่ยนเป้าหมายการนําเข้า แอปของคุณไม่จําเป็นต้องทราบว่าเป้าหมายการนําเข้าเป็นทรัพยากรที่รวม/คอมไพล์ หรือโครงสร้างการนำเข้า