核心要點
- 使用Promise異步加載圖片,允許同時加載不同圖片集合,並在集合加載完成後執行代碼。這通過減少整體加載時間來顯著提高網站性能。
- 此技術涉及為所有圖片“組”(集合)創建一個共享預加載器,該預加載器將要加載的圖片排隊。然後,預加載器並行(而非順序)開始加載圖片,避免必須等待一個組完成才能開始下一個組。
- 每個圖片URL都替換為一個Promise,該Promise在瀏覽器加載圖片後解析。然後,可以使用
Promise.all()
方法為每個組創建一個Promise,該Promise在數組中的所有Promise都解析後解析。 - 通過使用延遲Promise而不是回調來告訴預加載器在組加載完成後該做什麼,可以進一步改進該技術。這允許稍後控制Promise的解析。
本文探討一個具體問題:如何並行預加載大量圖片。 我最近遇到了這個問題,發現它比最初預期的更具挑戰性,也從中學習了很多。首先,讓我簡要描述一下場景。假設頁面上有幾個“組”。廣義上說,一個組就是一個圖片集合。我們希望預加載每個組的圖片,並能夠知道何時完成某個組的圖片加載。此時,我們可以自由運行任何我們想要的代碼,例如向組添加一個類、運行圖像序列、記錄某些內容等等。起初,這聽起來很簡單,甚至非常簡單。但是,你可能和我一樣忽略了一個細節:我們希望所有組並行加載,而不是順序加載。換句話說,我們不希望先加載組1的所有圖片,然後加載組2的所有圖片,再加載組3的所有圖片,依此類推。事實上,這不是理想的,因為最終會有一些組需要等待前面的組完成。因此,在一個場景中,如果第一個組有幾十張圖片,而第二個組只有一兩張圖片,我們就必須等待第一個組完全加載才能準備第二個組。這不好。我們肯定可以做得更好!所以我們的想法是並行加載所有組,這樣當一個組完全加載時,我們不必等待其他組。為此,大致思路是加載所有組的第一張圖片,然後加載所有組的第二張圖片,依此類推,直到所有圖片都已預加載。好了,讓我們從創建一些標記開始,這樣我們就能就正在發生的事情達成一致。
順便說一句,在本文中,我假設您熟悉Promise的概念。如果不是這樣,我建議您閱讀這篇文章。
標記
從標記的角度來看,一個組只不過是一個元素(例如div),帶有deck類以便我們可以定位它,以及一個包含圖片URL數組(作為JSON)的data-images屬性。
<div class="deck" data-images='["...", "...", "..."]'>...</div> <div class="deck" data-images='["...", "..."]'>...</div> <div class="deck" data-images='["...", "...", "...", "..."]'>...</div>
準備工作
在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();
我希望到目前為止,這是有意義的!
構建組
根據您想對組做什麼,這個“類”可能相當長。對於我們的場景,我們唯一要做的事情是在其圖片加載完成後向節點添加一個loaded類。 Deck函數沒有太多工作要做:1. 加載數據(從data-images屬性);2. 將數據添加到預加載器隊列的末尾;3. 告訴預加載器在數據預加載完成後該做什麼。
var Deck = function (node, preloader) { // 我们从`data-images`属性获取并解析数据 var data = JSON.parse(node.getAttribute('data-images')); // 我们调用预加载器的`queue`方法,将数据和回调函数传递给它 preloader.queue(data, function () { node.classList.add('loaded'); }); };
到目前為止,進展順利,不是嗎?唯一剩下的就是預加載器,儘管它也是本文中最複雜的代碼部分。
構建預加載器
我們已經知道我們的預加載器需要一個queue方法來將圖片集合添加到隊列中,以及一個preload方法來啟動預加載。它還需要一個輔助函數來預加載圖片,稱為preloadImage。讓我們從這裡開始:
var ImagePreloader = function () { ... }; ImagePreloader.prototype.queue = function () { ... } ImagePreloader.prototype.preloadImage = function () { ... } ImagePreloader.prototype.preload = function () { ... }
預加載器需要一個內部queue屬性來保存它必須預加載的組,以及它們各自的回調。
var ImagePreloader = function () { this.items = []; }
items是一個對像數組,其中每個對像有兩個鍵:- collection包含要預加載的圖片URL數組;- callback包含在組完全加載後要執行的函數。
知道了這一點,我們可以編寫queue方法。
<div class="deck" data-images='["...", "...", "..."]'>...</div> <div class="deck" data-images='["...", "..."]'>...</div> <div class="deck" data-images='["...", "...", "...", "..."]'>...</div>
好了。此時,每個組都可以將它的圖片添加到隊列中。我們現在必須構建preload方法,它將負責實際預加載圖片。但在跳轉到代碼之前,讓我們退一步來理解我們需要做什麼。我們的想法不是一個接一個地預加載每個組的所有圖片。我們的想法是預加載每個組的第一張圖片,然後是第二張,然後是第三張,依此類推。 預加載一張圖片意味著使用JavaScript(使用new Image())創建一個新的圖片,並為其應用一個src。這將提示瀏覽器異步加載源。由於這個異步過程,我們需要註冊一個Promise,該Promise在瀏覽器下載資源後解析。基本上,我們將用一個Promise替換我們數組中的每個圖片URL,該Promise在瀏覽器加載給定圖片後解析。此時,我們將能夠使用Promise.all(..) 來獲得一個最終的Promise,該Promise在數組中的所有Promise都解析後解析。對於每個組都是如此。讓我們從preloadImage方法開始:
// 实例化一个预加载器 var ip = new ImagePreloader(); // 从DOM获取所有组 var decks = document.querySelectorAll('.deck'); // 遍历它们并为每个组实例化一个新的组,将预加载器传递给每个组,以便组可以将它的图片添加到队列中 Array.prototype.slice.call(decks).forEach(function (deck) { new Deck(deck, ip); }); // 一旦所有组都将它们的项目添加到队列中,就预加载所有内容 ip.preload();
現在是preload方法。它做兩件事(因此可能可以拆分成兩個不同的函數,但這不在本文的範圍內):1. 它以特定的順序(每個組的第一張圖片,然後是第二張,然後是第三張……)將所有圖片URL替換為Promise;2. 對於每個組,它註冊一個Promise,當組中的所有Promise都解析後(!)調用組的回調。
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érian Galliat幫我解決這個問題。我們在這裡使用的是延遲Promise。延遲Promise不是原生Promise API的一部分,因此我們需要為其添加polyfill;謝天謝地,這只需要幾行代碼。基本上,延遲Promise是一個稍後可以解析的Promise。將其應用於我們的代碼,只會改變很少的東西。首先是.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演示鏈接,因為我無法直接嵌入CodePen)
結論
好了,朋友們。大約70行JavaScript代碼,我們就成功地異步並行加載了不同集合中的圖片,並在集合加載完成後執行了一些代碼。從這裡開始,我們可以做很多事情。在我的例子中,重點是在點擊按鈕時將這些圖片作為快速循環序列(gif樣式)運行。因此,我在加載期間禁用了按鈕,並在組完成所有圖片的預加載後重新啟用它。由於瀏覽器已經緩存了所有圖片,因此第一個循環運行非常流暢。我希望你喜歡它!您可以在GitHub上查看代碼,也可以直接在CodePen上使用它。 (此處應插入GitHub鏈接和CodePen鏈接)
(此處應添加FAQ部分,與輸入文本中的FAQ部分內容一致,但語言表達上進行了一些調整和潤色。)
以上是與承諾並行預加載圖像的詳細內容。更多資訊請關注PHP中文網其他相關文章!

JavaScript字符串替換方法詳解及常見問題解答 本文將探討兩種在JavaScript中替換字符串字符的方法:在JavaScript代碼內部替換和在網頁HTML內部替換。 在JavaScript代碼內部替換字符串 最直接的方法是使用replace()方法: str = str.replace("find","replace"); 該方法僅替換第一個匹配項。要替換所有匹配項,需使用正則表達式並添加全局標誌g: str = str.replace(/fi

本教程向您展示瞭如何將自定義的Google搜索API集成到您的博客或網站中,提供了比標準WordPress主題搜索功能更精緻的搜索體驗。 令人驚訝的是簡單!您將能夠將搜索限制為Y

因此,在這裡,您準備好了解所有稱為Ajax的東西。但是,到底是什麼? AJAX一詞是指用於創建動態,交互式Web內容的一系列寬鬆的技術。 Ajax一詞,最初由Jesse J創造

本文系列在2017年中期進行了最新信息和新示例。 在此JSON示例中,我們將研究如何使用JSON格式將簡單值存儲在文件中。 使用鍵值對符號,我們可以存儲任何類型的

利用輕鬆的網頁佈局:8 ESTISSEL插件jQuery大大簡化了網頁佈局。 本文重點介紹了簡化該過程的八個功能強大的JQuery插件,對於手動網站創建特別有用

核心要點 JavaScript 中的 this 通常指代“擁有”該方法的對象,但具體取決於函數的調用方式。 沒有當前對象時,this 指代全局對象。在 Web 瀏覽器中,它由 window 表示。 調用函數時,this 保持全局對象;但調用對象構造函數或其任何方法時,this 指代對象的實例。 可以使用 call()、apply() 和 bind() 等方法更改 this 的上下文。這些方法使用給定的 this 值和參數調用函數。 JavaScript 是一門優秀的編程語言。幾年前,這句話可

jQuery是一個很棒的JavaScript框架。但是,與任何圖書館一樣,有時有必要在引擎蓋下發現發生了什麼。也許是因為您正在追踪一個錯誤,或者只是對jQuery如何實現特定UI感到好奇

該帖子編寫了有用的作弊表,參考指南,快速食譜以及用於Android,BlackBerry和iPhone應用程序開發的代碼片段。 沒有開發人員應該沒有他們! 觸摸手勢參考指南(PDF)是Desig的寶貴資源


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

禪工作室 13.0.1
強大的PHP整合開發環境

Atom編輯器mac版下載
最受歡迎的的開源編輯器

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Dreamweaver Mac版
視覺化網頁開發工具