ホームページ > ウェブフロントエンド > jsチュートリアル > 約束と並行して画像をプリロードします

約束と並行して画像をプリロードします

Lisa Kudrow
リリース: 2025-02-19 11:01:13
オリジナル
395 人が閲覧しました

Preloading Images in Parallel with Promises

コアポイント

  • Promiseを使用して写真を非同期にロードし、さまざまな画像コレクションを同時にロードし、コレクションがロードされた後にコードを実行します。これにより、全体的な負荷時間を短縮することにより、ウェブサイトのパフォーマンスが大幅に向上します。
  • この手法では、すべての画像「グループ」(コレクション)に共有プレロダーを作成して、ロードする画像を列に並べることが含まれます。次に、Preloaderは写真のロードを並列に(順番ではなく)開始し、次のグループが開始される前に1つのグループが完了するのを待たなければならないことを避けます。
  • 各画像URLは約束に置き換えられます。これは、ブラウザが画像をロードした後に解析されます。その後、
  • メソッドを使用して、各グループに約束を作成できます。これは、配列内のすべての約束の後に解析されます。 Promise.all()
  • このテクノロジーは、コールバックの代わりに遅延した約束を使用して、グループがロードされた後に何をすべきかを伝えることにより、さらに改善できます。これにより、後で約束の解決を制御できます。
この記事では、特定の問題について説明します。多数の画像を並行してプリロードする方法について説明します。 私は最近この問題を抱えていますが、当初予想よりも挑戦的で、それから多くのことを学びました。まず、シーンを簡単に説明しましょう。ページにいくつかの「グループ」があるとします。大まかに言えば、グループは写真のコレクションです。各グループの画像をプリロードし、グループの画像がいつロードされるかを知ることができます。この時点で、グループにクラスを追加する、画像シーケンスの実行、何かの記録など、必要なコードを自由に実行できます。最初は、これはシンプルで、非常にシンプルに聞こえます。ただし、おそらく私のような詳細を1つ見落としていました。すべてのグループが、順次ではなく、並行してロードすることを望んでいます。言い換えれば、最初にグループ1のすべての写真、次にグループ2のすべての写真、次にグループ3のすべての写真などをロードしたくありません。実際、これは理想的ではありません。最終的に前のグループが完了するのを待つ必要があるグループがいくつかあるからです。したがって、シナリオでは、最初のグループに数十の写真があり、2番目のグループに1つまたは2つの写真しかない場合、2番目のグループを準備する前に最初のグループが完全にロードするのを待つ必要があります。これは良くありません。私たちは間違いなくもっとうまくやることができます!したがって、私たちのアイデアは、すべてのグループを並行してロードして、1つのグループが完全にロードされたときに他のグループを待つ必要がないようにすることです。これを行うために、一般的なアイデアは、すべてのグループの最初の画像をロードし、すべてのグループの2番目の画像をロードすることです。さて、何が起こっているかについて同意できるように、いくつかのマークアップを作成することから始めましょう。

ちなみに、この記事では、あなたが約束の概念に精通していると思います。そうでない場合は、この記事を読むことをお勧めします。

タグ

タグの観点から、グループは要素(例えば、div)にすぎず、デッキクラスを備えているので、それを見つけることができ、画像URLの配列を含むデータイメージプロパティ(jsonなど)。

<div class="deck" data-images='["...", "...", "..."]'>...</div>
<div class="deck" data-images='["...", "..."]'>...</div>
<div class="deck" data-images='["...", "...", "...", "..."]'>...</div>
ログイン後にコピー
ログイン後にコピー

準備

JavaScriptでは、これは予想通り、少し複雑です。 2つの異なるものを構築します:グループ

クラス(これを非常に大きな引用符の間に置いて、用語を選択しないでください)と

ツールを作成します。 Preloaderは、特定の順序でそれらをロードするためにすべてのグループのすべての写真を知る必要があるため、すべてのグループ間で共有する必要があります。グループは独自のプリロダーを持つことができません。そうでなければ、最初の問題が発生します。コードは順次実行されますが、これは私たちが望むものではありません。したがって、各グループに渡される前ローダーが必要です。後者はその画像をPreloaderのキューに追加し、すべてのグループがキューにアイテムを追加すると、Preloaderはプリロードを開始できます。コード実行スニペットは次のとおりです <em> </em>これまでのところ、これが理にかなっていることを願っています! </p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// 实例化一个预加载器 var ip = new ImagePreloader(); // 从DOM获取所有组 var decks = document.querySelectorAll('.deck'); // 遍历它们并为每个组实例化一个新的组,将预加载器传递给每个组,以便组可以将它的图片添加到队列中 Array.prototype.slice.call(decks).forEach(function (deck) { new Deck(deck, ip); }); // 一旦所有组都将它们的项目添加到队列中,就预加载所有内容 ip.preload();
ログイン後にコピー
ログイン後にコピー

build group

グループで何をしたいかによって、この「クラス」はかなり長いかもしれません。私たちのシナリオでは、私たちがしなければならない唯一のことは、その画像がロードされた後にノードにロードされたクラスを追加することです。デッキ機能には多くの作業がありません。1。データをロードします。プリロードされています。

これまでのところ、それは順調ですよね?残っている唯一のものはプリローダーですが、この記事のコードの最も複雑な部分でもあります。

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

  // 我们调用预加载器的`queue`方法,将数据和回调函数传递给它
  preloader.queue(data, function () {
    node.classList.add('loaded');
  });
};
ログイン後にコピー
ログイン後にコピー

Preloader

を構築します プリロダーには、キューコレクションをキューに追加するためのキューメソッドが必要であること、およびプリロードを開始するプリロードメソッドが必要であることがすでにわかっています。また、Preloadimageと呼ばれる画像をプリロードするためのヘルパー関数が必要です。ここから始めましょう:

Preloaderは、プリロードする必要があるグループとそれぞれのコールバックを保持するために内部キュープロパティを必要とします。

var ImagePreloader = function () { ... };
ImagePreloader.prototype.queue = function () { ... }
ImagePreloader.prototype.preloadImage = function () { ... }
ImagePreloader.prototype.preload = function () { ... }
ログイン後にコピー
ログイン後にコピー

アイテムは、各オブジェクトに2つのキーがあるオブジェクトの配列です。-コレクションには、プリロードされる画像URLの配列が含まれています。

これで、キューメソッドを書くことができます。
var ImagePreloader = function () {
  this.items = [];
}
ログイン後にコピー
ログイン後にコピー
<div class="deck" data-images='["...", "...", "..."]'>...</div>
<div class="deck" data-images='["...", "..."]'>...</div>
<div class="deck" data-images='["...", "...", "...", "..."]'>...</div>
ログイン後にコピー
ログイン後にコピー

わかりました。この時点で、各グループはその画像をキューに追加できます。これで、画像の実際のプリロードを担当するプリロードメソッドを構築する必要があります。しかし、コードにジャンプする前に、私たちが何をする必要があるかを理解するために戻ってみましょう。私たちのアイデアは、各グループのすべての写真を1つずつプリロードすることではありません。私たちのアイデアは、各グループの最初の画像、次に2番目の画像、次に3番目の画像などをプリロードすることです。 preload は、JavaScript(new Image()を使用して)を使用してSRCを適用して新しい画像を作成することを意味します。これにより、ブラウザがソースを非同期にロードするように促されます。この非同期プロセスにより、ブラウザがリソースをダウンロードした後に解析される約束を登録する必要があります。基本的に、配列内の各画像URLを、ブラウザが指定された画像をロードした後に解析するという約束に置き換えます。この時点で、Promise.all(..)を使用して、配列内のすべての約束の後に解析される最終的な約束を得ることができます。これはすべてのグループに当てはまります。プレロジメージメソッドから始めましょう:

// 实例化一个预加载器
var ip = new ImagePreloader();
// 从DOM获取所有组
var decks = document.querySelectorAll('.deck');

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

// 一旦所有组都将它们的项目添加到队列中,就预加载所有内容
ip.preload();
ログイン後にコピー

はプリロードメソッドです。それは2つのことを行います(したがって、2つの異なる関数に分割することは可能かもしれませんが、それはこの記事の範囲内ではありません):1。それは特定の順序です(各グループの最初の画像、次に2番目の画像、そしてそこにあります。 3番目のものです...)すべての画像URLを約束に置き換えます。各グループについて、それは約束を登録し、グループ内のすべての約束が解析された後にグループのコールバックを呼び出します。

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

  // 我们调用预加载器的`queue`方法,将数据和回调函数传递给它
  preloader.queue(data, function () {
    node.classList.add('loaded');
  });
};
ログイン後にコピー
ログイン後にコピー

それだけです!結局のところ、それはそれほど複雑ではありません、あなたは同意しますか?

その他のプロモーション

コードはうまく機能しますが、コールバックを使用して、グループがロードされた後に何をすべきかをプリロダーに伝えることはあまりエレガントではありません。特にPromiseを使用している場合は、コールバックの代わりにPromiseを使用することをお勧めします。この問題を解決する方法がわからないので、友人のValérianGalliatにこの問題を手伝ってくれるように頼んだことを認めなければなりません。ここで使用しているのは、Delay Promise です。遅延約束は、ネイティブの約束APIの一部ではないため、ありがたいことにポリフィルを追加する必要があります。基本的に、遅延約束は後で解析できる約束です。コードに適用すると、ほとんど変更されません。 1つ目は.queue(..)メソッドです:

var ImagePreloader = function () { ... };
ImagePreloader.prototype.queue = function () { ... }
ImagePreloader.prototype.preloadImage = function () { ... }
ImagePreloader.prototype.preload = function () { ... }
ログイン後にコピー
ログイン後にコピー

.preload(..)メソッドの分析:

var ImagePreloader = function () {
  this.items = [];
}
ログイン後にコピー
ログイン後にコピー
もちろん、最終的には、キューにデータを追加する方法です!

// 如果没有指定回调,则为空函数
function noop() {}

ImagePreloader.prototype.queue = function (array, callback) {
  this.items.push({
    collection: array,
    // 如果没有回调,我们推送一个no-op(空)函数
    callback: callback || noop
  });
};
ログイン後にコピー
完了です!コードが実際にどのように実行されているかを確認したい場合は、以下のデモをご覧ください。(Codepenデモリンクをここに挿入する必要があります。

結論

さて、友達。約70行のJavaScriptコードを使用して、異なるコレクションに写真を並行して非同期にロードし、コレクションのロード後にコードを実行しました。ここから、私たちにできることがたくさんあります。私の例では、ボタンがクリックされたときにこれらの画像をクイックループシーケンス(GIFスタイル)として実行することです。そのため、ロード中にボタンを無効にし、グループがすべての写真のプリロードを完了した後、再検討しました。ブラウザはすでにすべての画像をキャッシュしているため、最初のループは非常にスムーズに実行されます。気に入っていただければ幸いです! githubでコードを表示するか、Codepenで直接使用できます。 (GitHubリンクとCodepenリンクをここに挿入する必要があります)

(FAQパーツをここに追加する必要があります。これは、入力テキストのFAQパーツと一致していますが、言語式でいくつかの調整とポリッシュが行われています。)

以上が約束と並行して画像をプリロードしますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート