简体   繁体   English

等待图像在 JavaScript 中加载

[英]Waiting for image to load in JavaScript

I'm making an Ajax call which returns me some info including an image path.我正在进行 Ajax 调用,它会返回一些信息,包括图像路径。

I prepare all this information in my HTML which will be displayed as a kind of popup.我在我的 HTML 中准备了所有这些信息,这些信息将显示为一种弹出窗口。 I just toggle the visibility of by popup div from hidden to visible.我只是将弹出 div 的可见性从隐藏切换到可见。

To set the position of my popup div, I have to calculate depending on the height of the image.要设置弹出 div 的位置,我必须根据图像的高度进行计算。 So, I have to wait for the image to load to know its dimension before setting position and switching visibility to visible.因此,在设置位置并将可见性切换为可见之前,我必须等待图像加载以了解其尺寸。

I tried tricks with recursion, setTimeout, complete img property, while loop... without success.我尝试了递归,setTimeout,完整的img属性,while循环的技巧......但没有成功。

So, how can I do this?那么,我该怎么做呢? Maybe I should return dimensions in my Ajax call.也许我应该在我的 Ajax 调用中返回尺寸。

var img = new Image();
img.onload = function() { alert("Height: " + this.height); }
img.src = "http://path/to/image.jpg";

Note that it's important to do it in the order above: First attach the handler, then set the src .请注意,按上述顺序执行此操作很重要:首先附加处理程序,然后设置src If you do it the other way around, and the image is in cache, you may miss the event.如果您以相反的方式执行此操作,并且图像在缓存中,您可能会错过该事件。 JavaScript is run on a single thread in browsers (unless you're using web workers), but browsers are not single-threaded. JavaScript 在浏览器中的单线程上运行(除非您使用网络工作者),但浏览器不是单线程的。 It's perfectly valid for the browser to see the src , identify the resource is available, load it, trigger the event, look at the element to see if it has any handlers that need to be queued for callback, not see any, and complete the event processing, all between the src line and the line attaching the handler.浏览器看到src ,识别资源可用,加载它,触发事件,查看元素以查看它是否有任何需要排队等待回调的处理程序,没有看到任何处理程序,并完成事件处理,都在src行和附加处理程序的行之间。 (The callbacks wouldn't happen between the lines if they were registered, they'd wait in the queue, but if there aren't any, the event isn't required to wait.) (如果它们被注册,回调将不会在行之间发生,它们会在队列中等待,但如果没有,则事件不需要等待。)

If you use jQuery, you can use its load event.如果你使用 jQuery,你可以使用它的load事件。

Have a look at the example:看看这个例子:

$('img.userIcon').load(function(){
    if($(this).height() > 100) {
        $(this).addClass('bigImg');
    }
});

The accepted answer is outdated but does show the basic Image#onload callback approach.接受的答案已过时,但确实显示了基本的Image#onload回调方法。 Nowadays, you'll likely want to promisify the image load to avoid callback hell.如今,您可能希望承诺图像加载以避免回调地狱。

This answer is a good shot at promisifying the image onload handler, but is missing some key points as my comment indicates.这个答案很好地说明了图像加载处理程序,但正如我的评论所指出的那样,它缺少一些关键点。

Here's another promisification of Image that is a bit more general.这是Image的另一个更通用的承诺。 Rejecting in the onerror handler and passing the actual image object into the resolver are important to make the function minimally reusable.onerror处理程序中拒绝并将实际的图像对象传递给解析器对于使函数具有最小的可重用性很重要。

Improvements might include additional parameters (such as crossOrigin , for example).改进可能包括其他参数(例如crossOrigin )。 A settings object or providing an Image as a parameter is another approach to generalize the function (setting src fires the request, so that should go last after handlers have been added). settings对象或提供Image作为参数是另一种泛化函数的方法(设置src会触发请求,因此应该在添加处理程序后最后执行)。

 const loadImage = src => new Promise((resolve, reject) => { const img = new Image(); img.onload = () => resolve(img); img.onerror = reject; img.src = src; }) ; loadImage("http://placekitten.com/90/100").then(image => console.log(image, `\nloaded? ${image.complete}`) );

With the above function, Promise.all can be used to load a batch of images in parallel ( Promise.allSettled is useful if you want to keep going even if some images don't load).通过上述功能, Promise.all可用于并行加载一批图像(如果您想在某些图像未加载的情况下继续运行, Promise.allSettled很有用)。

 const loadImage = src => new Promise((resolve, reject) => { const img = new Image(); img.onload = () => resolve(img); img.onerror = reject; img.src = src; }) ; const imageUrls = [ "http://placekitten.com/85/150", "http://placekitten.com/85/130", "http://placekitten.com/85/110", ]; Promise.all(imageUrls.map(loadImage)).then(images => { const canvas = document.createElement("canvas"); document.body.appendChild(canvas); const ctx = canvas.getContext("2d"); images.forEach((image, i) => ctx.drawImage(image, i * 90, 0, image.width, image.height) ); });

just wrap your image onload in a function with a promise and then call it with await.只需将您的图像 onload 包装在一个带有 promise 的函数中,然后使用 await 调用它。

async drawImg(ctx, image){

    return new Promise(resolve => {

          image.onload = function () {
                ctx.drawImage(image, 10, 10, 200, 180);
                resolve('resolved');
             }

    });

  }

it should work just fine它应该可以正常工作

How about the window load event?窗口加载事件怎么样?

window.addEventListener('load', (event) => {
  //do stuff with images
});

or或者

window.onload = (event) => {
  //do stuff with images
};

https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event

This worked for me where I needed the browser to calculate the size of the images before running a layout script.这对我有用,我需要浏览器在运行布局脚本之前计算图像的大小。

Promise example of waiting for image loading, waits for loading or fail.等待图像加载,等待加载或失败的 Promise 示例。 Does not rejects:不拒绝:

 function waitForImage(imgElem) { return new Promise(res => { if (imgElem.complete) { return res(); } imgElem.onload = () => res(); imgElem.onerror = () => res(); }); } // test (async () => { const img = document.querySelector('img'); // to not to cache in the test, set src dynamically img.src = 'https://www.gravatar.com/avatar/71094909be9f40bd576b1974a74966aa?s=48&d=identicon&r=PG&f=1'; console.log('height before', img.naturalHeight); // 0 await waitForImage(img); console.log('height after', img.naturalHeight); // 48 })();
 <img src=""/>

Version with reject, if you need to know, if its failed:带有拒绝的版本,如果您需要知道,如果它失败:

 function waitForImage(imgElem) { return new Promise((res, rej) => { if (imgElem.complete) { return res(); } imgElem.onload = () => res(); imgElem.onerror = () => rej(imgElem); }); } // test (async () => { const img = document.querySelector('#rightone'); // to not to cache in the test, set src dynamically img.src = 'https://www.gravatar.com/avatar/71094909be9f40bd576b1974a74966aa?s=48&d=identicon&r=PG&f=1'; console.log('height before', img.naturalHeight); // 0 await waitForImage(img); // success console.log('height after', img.naturalHeight); // 48 try { const failImg = document.querySelector('#wrongone'); failImg.src = 'https://wrongimage'; await waitForImage(failImg); // rejects after some time } catch(e) { console.log('failed to load image', e) } })();
 <img id="rightone" src=""> <img id="wrongone" src="">

I had a slow CAPTCHA (1st_image) image loading on my page and I wanted to display another image (2nd_image) only AFTER the CAPTCHA image (1st_image) is loaded.我的页面上加载了缓慢的 CAPTCHA (1st_image) 图像,我想仅在加载 CAPTCHA 图像 (1st_image) 后显示另一个图像 (2nd_image)。 So I had to wait for the CAPTCHA (1st_image) image to load first.所以我不得不等待 CAPTCHA (1st_image) 图像首先加载。

Here is the solution that works perfectly fine to wait for an image to load first and then load another image (don't forget to display a "please wait!" image while they are waiting for other image to load):这是一个非常有效的解决方案,可以先等待图像加载,然后再加载另一个图像(不要忘记在他们等待其他图像加载时显示“请稍候!”图像):

<script>
    function checkImageLoad() {
        if (document.getElementById("1st_image").complete == true) {
            console.log("1st_image Loaded!");
        }
        document.getElementById("2nd_image").src = "http://example.org/2nd_image.png";
    }
</script>
<body onload="checkImageLoad();">
<img id="1st_image" src="http://example.org/1st_image.png">
<img id="2nd_image" src="http://example.org/loading_please_wait.gif">

Either the Internet speed is slow or fast, and the browser will wait for the whole page to load with all the images (even if they are linked externally) and then execute the function, so the second image is displayed only after the first image loads fine.要么网速慢要么快,浏览器会等待整个页面加载完所有图片(即使它们是外部链接的)然后执行函数,所以只有在第一张图片加载后才会显示第二张图片美好的。

Advanced note: You can use a web page URL in the "src" of the image to load a web page first and then show the image.高级说明:您可以在图片的“src”中使用网页网址,先加载网页,然后再显示图片。 The purpose is to load the cookie from the external webpage which might effect the second image displayed (like CAPTCHA) .目的是从外部网页加载 cookie,这可能会影响显示的第二张图像(如 CAPTCHA)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM