Rumah >hujung hadapan web >tutorial js >Imej preloading selari dengan janji

Imej preloading selari dengan janji

Lisa Kudrow
Lisa Kudrowasal
2025-02-19 11:01:13398semak imbas

Preloading Images in Parallel with Promises

mata teras

    Gunakan Janji untuk memuatkan gambar secara asynchronously, membolehkan koleksi imej yang berbeza dimuatkan pada masa yang sama, dan melaksanakan kod selepas koleksi dimuatkan. Ini meningkatkan prestasi laman web dengan ketara dengan mengurangkan masa beban keseluruhan.
  • Teknik ini melibatkan membuat preloader bersama untuk semua "kumpulan" imej (koleksi) yang beratur imej untuk dimuatkan. Preloader kemudian mula memuatkan gambar secara selari (bukan dalam urutan), mengelakkan perlu menunggu satu kumpulan selesai sebelum kumpulan seterusnya dimulakan.
  • Setiap URL imej digantikan dengan janji, yang dihuraikan selepas penyemak imbas memuat imej. Anda kemudian boleh menggunakan kaedah
  • untuk membuat janji untuk setiap kumpulan, yang dihuraikan selepas semua janji dalam array. Promise.all()
  • Teknologi ini dapat diperbaiki lagi dengan menggunakan janji yang tertunda dan bukannya panggilan balik untuk memberitahu preloader apa yang perlu dilakukan selepas kumpulan dimuatkan. Ini membolehkan kawalan kemudian resolusi janji.
Artikel ini membincangkan masalah tertentu: Bagaimana untuk memaksimumkan sejumlah besar imej selari. Saya mempunyai masalah ini baru -baru ini dan mendapati ia lebih mencabar daripada yang dijangka pada awalnya dan belajar banyak daripadanya. Pertama, izinkan saya menerangkan secara ringkas tempat kejadian. Katakan terdapat beberapa "kumpulan" pada halaman. Secara umum, kumpulan adalah koleksi gambar. Kami mahu memaparkan imej untuk setiap kumpulan dan dapat mengetahui bila imej untuk kumpulan dimuatkan. Pada ketika ini, kita boleh menjalankan sebarang kod yang kita mahu, seperti menambahkan kelas kepada kumpulan, menjalankan urutan imej, merakam sesuatu, dll. Pada mulanya, ini mudah, walaupun sangat mudah. Walau bagaimanapun, anda mungkin terlepas pandang satu butiran seperti saya: kami mahu semua kumpulan dimuatkan secara selari, tidak berurutan. Dengan kata lain, kami tidak mahu memuatkan semua gambar Kumpulan 1 Pertama, maka semua gambar Kumpulan 2, maka semua gambar Kumpulan 3, dan sebagainya. Malah, ini tidak sesuai, kerana terdapat beberapa kumpulan yang akhirnya perlu menunggu kumpulan sebelumnya selesai. Oleh itu, dalam senario, jika kumpulan pertama mempunyai berpuluh -puluh gambar dan kumpulan kedua hanya mempunyai satu atau dua gambar, kita perlu menunggu kumpulan pertama untuk memuat sepenuhnya sebelum kita dapat menyediakan kumpulan kedua. Ini tidak bagus. Kita pasti dapat melakukan yang lebih baik! Oleh itu, idea kami adalah untuk memuatkan semua kumpulan secara selari supaya apabila satu kumpulan dimuatkan sepenuhnya, kami tidak perlu menunggu kumpulan lain. Untuk melakukan ini, idea umum adalah untuk memuat imej pertama semua kumpulan, kemudian memuatkan imej kedua semua kumpulan, dan sebagainya sehingga semua gambar dimuatkan. Ok, mari kita mulakan dengan membuat beberapa markup supaya kita boleh bersetuju dengan apa yang sedang berlaku.

Dengan cara ini, dalam artikel ini, saya menganggap anda sudah biasa dengan konsep janji. Jika itu tidak berlaku, saya cadangkan anda membaca artikel ini.

tags

Dari sudut pandangan tag, kumpulan tidak lebih dari satu elemen (mis. Div), dengan kelas dek supaya kita dapat mencarinya, dan harta data-imej yang mengandungi pelbagai URL imej (sebagai JSON ).

<code class="language-html"><div class="deck" data-images='["...", "...", "..."]'>...</div>
<div class="deck" data-images='["...", "..."]'>...</div>
<div class="deck" data-images='["...", "...", "...", "..."]'>...</div></code>

Penyediaan

Dalam JavaScript, ini - seperti yang diharapkan - agak rumit. Kami akan membina dua perkara yang berbeza: kumpulan kelas (sila letakkan ini di antara petikan yang sangat besar dan jangan pilih istilah) dan alat preloader . Kerana preloader mesti tahu semua gambar semua kumpulan untuk memuatkannya dalam urutan tertentu, ia perlu dikongsi di kalangan semua kumpulan. Kumpulan tidak boleh mempunyai preloader sendiri, jika tidak, kita akan mempunyai masalah awal: kod itu dilaksanakan secara berurutan, yang bukan apa yang kita mahu. Oleh itu, kita memerlukan preloader yang diluluskan kepada setiap kumpulan. Yang terakhir menambah imejnya ke barisan preloader, dan apabila semua kumpulan menambah item mereka ke barisan, preloader boleh memulakan preloading. Coretan pelaksanaan kod adalah seperti berikut:

<code class="language-javascript">// 实例化一个预加载器
var ip = new ImagePreloader();
// 从DOM获取所有组
var decks = document.querySelectorAll('.deck');

// 遍历它们并为每个组实例化一个新的组,将预加载器传递给每个组,以便组可以将它的图片添加到队列中
Array.prototype.slice.call(decks).forEach(function (deck) {
  new Deck(deck, ip);
});

// 一旦所有组都将它们的项目添加到队列中,就预加载所有内容
ip.preload();</code>

Saya harap setakat ini, ini masuk akal!

Build Group

Bergantung pada apa yang anda mahu lakukan dengan kumpulan, "kelas" ini mungkin agak lama. Untuk senario kami, satu -satunya perkara yang perlu kita lakukan ialah menambah kelas yang dimuatkan ke nod selepas imejnya dimuatkan. Tidak banyak kerja yang perlu dilakukan dalam fungsi dek: 1. Muatkan data (dari harta data); dimuatkan.

<code class="language-javascript">var Deck = function (node, preloader) {
  // 我们从`data-images`属性获取并解析数据
  var data = JSON.parse(node.getAttribute('data-images'));

  // 我们调用预加载器的`queue`方法,将数据和回调函数传递给它
  preloader.queue(data, function () {
    node.classList.add('loaded');
  });
};</code>

Setakat ini, ia berjalan lancar, bukan? Satu -satunya perkara yang tersisa adalah preloader, walaupun ia juga merupakan bahagian yang paling kompleks dalam kod dalam artikel ini.

Bina preloader

Kami sudah tahu bahawa preloader kami memerlukan kaedah giliran untuk menambah koleksi imej ke barisan, dan kaedah preload untuk memulakan preload. Ia juga memerlukan fungsi penolong untuk memelihara imej, yang dipanggil preloadimage. Mari mulakan di sini:

<code class="language-javascript">var ImagePreloader = function () { ... };
ImagePreloader.prototype.queue = function () { ... }
ImagePreloader.prototype.preloadImage = function () { ... }
ImagePreloader.prototype.preload = function () { ... }</code>

Preloader memerlukan harta giliran dalaman untuk memegang kumpulan yang mesti dipredikasikan, dan panggilan balik masing -masing.

<code class="language-javascript">var ImagePreloader = function () {
  this.items = [];
}</code>

item adalah pelbagai objek, di mana setiap objek mempunyai dua kunci: - Koleksi mengandungi pelbagai URL imej yang akan dimuatkan;

Dengan ini, kita boleh menulis kaedah giliran.

<code class="language-html"><div class="deck" data-images='["...", "...", "..."]'>...</div>
<div class="deck" data-images='["...", "..."]'>...</div>
<div class="deck" data-images='["...", "...", "...", "..."]'>...</div></code>

Baiklah. Pada ketika ini, setiap kumpulan boleh menambah imejnya ke barisan. Kami kini perlu membina kaedah preload, yang akan bertanggungjawab untuk pramuat imej sebenar. Tetapi sebelum melompat ke kod, mari kita mundur untuk memahami apa yang perlu kita lakukan. Idea kami bukanlah untuk memuatkan semua gambar setiap kumpulan satu demi satu. Idea kami adalah untuk memuatkan imej pertama setiap kumpulan, maka imej kedua, kemudian imej ketiga, dan sebagainya. Preload Imej bermaksud membuat imej baru menggunakan JavaScript (menggunakan imej baru ()) dan memohon SRC kepadanya. Ini akan mendorong penyemak imbas untuk memuatkan sumber secara asynchronously. Oleh kerana proses tak segerak ini, kita perlu mendaftarkan janji, yang dihuraikan selepas penyemak imbas memuat turun sumber. Pada asasnya, kami akan menggantikan setiap URL imej dalam array kami dengan janji bahawa parses selepas penyemak imbas memuat imej yang diberikan. Pada ketika ini, kita akan dapat menggunakan janji. Semua (..) untuk mendapatkan janji akhir yang dihuraikan selepas semua janji dalam array. Ini benar untuk setiap kumpulan. Mari kita mulakan dengan kaedah preloadimage:

<code class="language-javascript">// 实例化一个预加载器
var ip = new ImagePreloader();
// 从DOM获取所有组
var decks = document.querySelectorAll('.deck');

// 遍历它们并为每个组实例化一个新的组,将预加载器传递给每个组,以便组可以将它的图片添加到队列中
Array.prototype.slice.call(decks).forEach(function (deck) {
  new Deck(deck, ip);
});

// 一旦所有组都将它们的项目添加到队列中,就预加载所有内容
ip.preload();</code>

sekarang adalah kaedah preload. Ia melakukan dua perkara (jadi mungkin dapat dibahagikan kepada dua fungsi yang berbeza, tetapi itu tidak dalam skop artikel ini): 1. Ia dalam urutan tertentu (imej pertama setiap kumpulan, kemudian yang kedua, kemudian di sana adalah yang ketiga ...) menggantikan semua URL imej dengan janji; untuk setiap kumpulan, ia mendaftarkan janji, dan memanggil panggilan balik kumpulan selepas semua janji dalam kumpulan itu dihuraikan (!).

<code class="language-javascript">var Deck = function (node, preloader) {
  // 我们从`data-images`属性获取并解析数据
  var data = JSON.parse(node.getAttribute('data-images'));

  // 我们调用预加载器的`queue`方法,将数据和回调函数传递给它
  preloader.queue(data, function () {
    node.classList.add('loaded');
  });
};</code>

itu sahaja! Lagipun, itu tidak rumit, adakah anda bersetuju?

lebih banyak promosi

Kod ini berfungsi dengan baik, walaupun menggunakan panggil balik untuk memberitahu preloader apa yang perlu dilakukan selepas kumpulan dimuatkan tidak begitu elegan. Anda mungkin mahu menggunakan Janji dan bukannya panggilan balik, terutamanya jika kami menggunakan Janji! Saya tidak pasti bagaimana menyelesaikan masalah ini, jadi saya harus mengakui bahawa saya bertanya kepada rakan saya Valérian Galliat untuk membantu saya menghadapi masalah ini. Apa yang kita gunakan di sini ialah Janji Kelewatan . Janji yang ditangguhkan bukanlah sebahagian daripada API Janji Asli, jadi kita perlu menambah polyfills kepadanya; Pada asasnya, janji yang tertunda adalah janji yang boleh dihuraikan kemudian. Memohon kepada kod kami hanya akan berubah sedikit. Pertama ialah kaedah .queue(..):

<code class="language-javascript">var ImagePreloader = function () { ... };
ImagePreloader.prototype.queue = function () { ... }
ImagePreloader.prototype.preloadImage = function () { ... }
ImagePreloader.prototype.preload = function () { ... }</code>
Analisis dalam kaedah

.preload(..):

<code class="language-javascript">var ImagePreloader = function () {
  this.items = [];
}</code>

Sudah tentu, pada akhirnya, bagaimana kita menambah data ke barisan!

<code class="language-javascript">// 如果没有指定回调,则为空函数
function noop() {}

ImagePreloader.prototype.queue = function (array, callback) {
  this.items.push({
    collection: array,
    // 如果没有回调,我们推送一个no-op(空)函数
    callback: callback || noop
  });
};</code>

Kami sudah selesai! Jika anda ingin melihat bagaimana kod itu sebenarnya berjalan, periksa demo di bawah: (pautan demo codepen harus dimasukkan di sini, kerana saya tidak dapat membenamkan codepen secara langsung)

Kesimpulan

Baiklah, kawan -kawan. Dengan kira -kira 70 baris kod JavaScript, kami berjaya memuatkan gambar dalam koleksi yang berbeza secara asynchronously dan melaksanakan beberapa kod selepas koleksi dimuatkan. Dari sini, terdapat banyak perkara yang boleh kita lakukan. Dalam contoh saya, tumpuannya adalah untuk menjalankan imej ini sebagai urutan gelung cepat (gaya GIF) apabila butang diklik. Oleh itu, saya melumpuhkan butang semasa memuatkan dan mengaktifkannya semula selepas kumpulan itu selesai memaksimumkan semua gambar. Oleh kerana penyemak imbas sudah cache semua imej, gelung pertama berjalan dengan lancar. Saya harap anda menyukainya! Anda boleh melihat kod di GitHub atau menggunakannya secara langsung pada Codepen. (Pautan github dan pautan codepen hendaklah dimasukkan di sini)

(bahagian Soalan Lazim harus ditambah di sini, yang konsisten dengan bahagian FAQ dalam teks input, tetapi beberapa pelarasan dan pengilat telah dibuat dalam ungkapan bahasa.)

Atas ialah kandungan terperinci Imej preloading selari dengan janji. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel sebelumnya:Pengenalan kepada Stage.jsArtikel seterusnya:Pengenalan kepada Stage.js