Ответ 1
Да. Это должно работать на всех основных браузерах.
Достаточно ли написанной ниже функции для предварительной загрузки изображений в большинстве, если не во всех браузерах, обычно используемых сегодня?
function preloadImage(url)
{
var img=new Image();
img.src=url;
}
У меня есть массив URL-адресов изображений, которые я зацикливаю и preloadImage
функцию preloadImage
для каждого URL-адреса.
Да. Это должно работать на всех основных браузерах.
Попробуй, я думаю, это лучше.
var images = [];
function preload() {
for (var i = 0; i < arguments.length; i++) {
images[i] = new Image();
images[i].src = preload.arguments[i];
}
}
//-- usage --//
preload(
"http://domain.tld/gallery/image-001.jpg",
"http://domain.tld/gallery/image-002.jpg",
"http://domain.tld/gallery/image-003.jpg"
)
Источник: http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/
Альтернатива CSS2: http://www.thecssninja.com/css/even-better-image-preloading-with-css2
body:after {
content: url(img01.jpg) url(img02.jpg) url(img03.jpg);
display: none;
}
Альтернатива CSS3: https://perishablepress.com/preload-images-css3/ (H/T Linh Dam)
.preload-images {
display: none;
width: 0;
height: 0;
background: url(img01.jpg),
url(img02.jpg),
url(img03.jpg);
}
ПРИМЕЧАНИЕ. Изображения в контейнере с display:none
не может быть предварительно загружен. Возможно видимость: скрытый будет работать лучше, но я не проверял это. Спасибо Marco Del Valle за указание на это
В моем случае было полезно добавить обратный вызов в вашу функцию для события onload
:
function preloadImage(url, callback)
{
var img=new Image();
img.src=url;
img.onload = callback;
}
А затем оберните его для случая массива URL-адресов к изображениям, которые должны быть предварительно загружены с обратным вызовом на все готово: https://jsfiddle.net/4r0Luoy7/
function preloadImages(urls, allImagesLoadedCallback){
var loadedCounter = 0;
var toBeLoadedNumber = urls.length;
urls.forEach(function(url){
preloadImage(url, function(){
loadedCounter++;
console.log('Number of loaded images: ' + loadedCounter);
if(loadedCounter == toBeLoadedNumber){
allImagesLoadedCallback();
}
});
});
function preloadImage(url, anImageLoadedCallback){
var img = new Image();
img.onload = anImageLoadedCallback;
img.src = url;
}
}
// Let call it:
preloadImages([
'//upload.wikimedia.org/wikipedia/commons/d/da/Internet2.jpg',
'//www.csee.umbc.edu/wp-content/uploads/2011/08/www.jpg'
], function(){
console.log('All images were loaded');
});
Этот подход немного более сложный. Здесь вы сохраняете все предварительно загруженные изображения в контейнере, может быть div. И после того, как вы сможете показать изображения или переместить их в DOM в правильное положение.
function preloadImg(containerId, imgUrl, imageId) {
var i = document.createElement('img'); // or new Image()
i.id = imageId;
i.onload = function() {
var container = document.getElementById(containerId);
container.appendChild(this);
};
i.src = imgUrl;
}
Попробуйте здесь, я также добавил несколько комментариев
Я рекомендую использовать try/catch для предотвращения возможных проблем:
OOP:
var preloadImage = function (url) {
try {
var _img = new Image();
_img.src = url;
} catch (e) { }
}
Стандарт:
function preloadImage (url) {
try {
var _img = new Image();
_img.src = url;
} catch (e) { }
}
Кроме того, в то время как я люблю DOM, у старых глупых браузеров могут возникнуть проблемы с вами, используя DOM, поэтому вообще избегайте их ИМХО, вопреки тому, что он сказал. Image() имеет лучшую поддержку в старых браузерах корзины.
Да, это будет работать, однако браузеры будут ограничить (между 4-8) действительными вызовами и, следовательно, не кэшировать/предварительно загружать все нужные изображения.
Лучший способ сделать это - вызвать onload перед использованием изображения следующим образом:
function (imageUrls, index) {
var img = new Image();
img.onload = function () {
console.log('isCached: ' + isCached(imageUrls[index]));
*DoSomething..*
img.src = imageUrls[index]
}
function isCached(imgUrl) {
var img = new Image();
img.src = imgUrl;
return img.complete || (img .width + img .height) > 0;
}
Вот мой подход:
var preloadImages = function (srcs, imgs, callback) {
var img;
var remaining = srcs.length;
for (var i = 0; i < srcs.length; i++) {
img = new Image;
img.onload = function () {
--remaining;
if (remaining <= 0) {
callback();
}
};
img.src = srcs[i];
imgs.push(img);
}
};
Я могу подтвердить, что подход в вопросе достаточен для запуска загрузки и кэширования изображений (если только вы не запретили браузеру делать это через заголовки ответа), по крайней мере:
Чтобы проверить это, я сделал небольшое веб-приложение с несколькими конечными точками, каждое из которых спит по 10 секунд, прежде чем подать фотографию котенка. Затем я добавил две веб-страницы, одна из которых содержала <script>
в котором каждый из котят предварительно preloadImage
с помощью функции preloadImage
из вопроса, а другая preloadImage
всех котят на странице с помощью тегов <img>
.
Во всех браузерах, указанных выше, я обнаружил, что если я сначала зашел на страницу предварительного загрузчика, немного подождал, а затем перешел на страницу с тегами <img>
, мои котята визуализировались мгновенно. Это показывает, что прелоадер успешно загрузил котят в кеш во всех протестированных браузерах.
Вы можете посмотреть или опробовать приложение, которое я использовал для проверки этого, на https://github.com/ExplodingCabbage/preloadImage-test.
В частности, обратите внимание, что этот метод работает в указанных выше браузерах, даже если количество зацикленных изображений превышает количество параллельных запросов, которые браузер хочет сделать за раз, вопреки тому, что предлагает ответ Робина. Скорость предварительной загрузки изображений, конечно, будет ограничена количеством параллельных запросов, которые браузер желает отправить, но в конечном итоге будет запрашивать каждый URL-адрес изображения, для которого вы вызываете preloadImage()
.
Примечание: это также будет работать, если вы используете транспортер, такой как Babel.
'use strict';
function imageLoaded(src, alt = '') {
return new Promise(function(resolve) {
const image = document.createElement('img');
image.setAttribute('alt', alt);
image.setAttribute('src', src);
image.addEventListener('load', function() {
resolve(image);
});
});
}
async function runExample() {
console.log("Fetching my cat image...");
const myCat = await imageLoaded('https://placekitten.com/500');
console.log("My cat image is ready! Now is the time to load my dog image...");
const myDog = await imageLoaded('https://placedog.net/500');
console.log('Whoa! This is now the time to enable my galery.');
document.body.appendChild(myCat);
document.body.appendChild(myDog);
}
runExample();
Вы также могли дождаться загрузки всех изображений одновременно.
async function runExample() {
const [myCat, myDog] = [
await imageLoaded('https://placekitten.com/500'),
await imageLoaded('https://placedog.net/500')
];
document.body.appendChild(myCat);
document.body.appendChild(myDog);
}
предварительно загрузите массив изображений в DOM в нижней части элемента body
function preloadImages(srcArray) {
for (var i = 0, len = srcArray.length; i < len; i++) {
var img = new Image();
img.src = srcArray[i];
img.style.display = 'none';
document.body.appendChild(img);
}
}
пример использования:
preloadImages([
'public/img/img1.png',
'public/img/img2.png'
]
)