使用Promise()在网络浏览器上加载图像

Abh*_*ant 2 javascript html5-canvas es6-promise

我正在尝试从此处学习如何在JavaScript中制作SuperMario, 有人可以解释下面函数LoadImage的流程吗?

function loadImage(url) {
        return new  Promise(resolve => {
            const image = new Image();
            image.addEventListener('load', () => {
                resolve(image);
            });
            image.src = url; 
        });
}

const canvas = document.getElementById('screen');
const context = canvas.getContext('2d');

context.fillRect(0,0,50,50);

loadImage('/img/tiles.png')
.then(image=>{
    context.drawImage(image,0,0);  // the function LoadImage returns a Promise with image object(which is  a constant)
// as parameter and if the promise is fulfilled then the image is drawn. 
/
});
Run Code Online (Sandbox Code Playgroud)

编辑

我确实了解如何使用=>运算符。用于缩短函数的长度。

image.addEventListener('load', () => {
                resolve(image);
Run Code Online (Sandbox Code Playgroud)

上一行表示在加载图像时实现了诺言。那么这是否意味着执行以下行,然后事件侦听器正在等待在客户端浏览器中下载图像?

image.scr = url;
Run Code Online (Sandbox Code Playgroud)

以下功能的流程对我来说有点模糊

function loadImage(url) {
        return new  Promise(resolve => {
            const image = new Image();
            image.addEventListener('load', () => {
                resolve(image);
            });
            image.src = url; 
        });
Run Code Online (Sandbox Code Playgroud)

编辑2:

好的,这是一个愚蠢的帖子。是的,当url中的IMAGE加载到图像对象中时,事件侦听器将启动resolve()。

zer*_*298 9

您所显示的代码引入了一个异步原语Promise,该原语可以传递并用于访问尚未填充的资源。

在这种情况下,您需要一个Image已完全加载并具有可以使用的图像数据的。但是,您将无法访问图像数据,直到完成将获取图像数据的网络请求为止。

例如,这将不起作用:

const img = new Image();
img.src = "example.com/house.jpg";
ctx.drawImage(img, 0, 0); // img isn't done loading yet
Run Code Online (Sandbox Code Playgroud)

相反,我们必须等到加载完成。有很多方法可以做到这一点,但是最常见的约定是使用,回调,Promises或async / await。

您显示的方法结合了回调和Promises(不必要)。

让我们分解一下代码:

/**
 * Load an image from a given URL
 * @param {String} url The URL of the image resource
 * @returns {Promise<Image>} The loaded image
 */
function loadImage(url) {
  /*
   * We are going to return a Promise which, when we .then
   * will give us an Image that should be fully loaded
   */
  return new Promise(resolve => {
    /*
     * Create the image that we are going to use to
     * to hold the resource
     */
    const image = new Image();
    /*
     * The Image API deals in even listeners and callbacks
     * we attach a listener for the "load" event which fires
     * when the Image has finished the network request and
     * populated the Image with data
     */
    image.addEventListener('load', () => {
      /*
       * You have to manually tell the Promise that you are
       * done dealing with asynchronous stuff and you are ready
       * for it to give anything that attached a callback
       * through .then a realized value.  We do that by calling
       * resolve and passing it the realized value
       */
      resolve(image);
    });
    /*
     * Setting the Image.src is what starts the networking process
     * to populate an image.  After you set it, the browser fires
     * a request to get the resource.  We attached a load listener
     * which will be called once the request finishes and we have
     * image data
     */
    image.src = url;
  });
}

/*
 * To use this we call the loadImage function and call .then
 * on the Promise that it returns, passing a function that we
 * want to receive the realized Image
 */
loadImage("example.com/house.jpg").then(houseImage => {
  ctx.drawImage(houseImage, 0, 0);
});
Run Code Online (Sandbox Code Playgroud)


坦白说,该loadImage函数可能会更健壮,因为它现在不处理错误。考虑以下增强功能:

function loadImage(src) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.addEventListener("load", () => resolve(img));
    img.addEventListener("error", err => reject(err));
    img.src = src;
  });
};

loadImage("example.com/house.jpg")
  .then(img => console.log(`w: ${img.width} | h: ${img.height}`))
  .catch(err => console.error(err));
Run Code Online (Sandbox Code Playgroud)

  • 我提出问题的方式难以理解。我没想到会有任何答案,但您先生花了一些时间来回答我的问题。我今天获得了新的知识。谢谢你。 (6认同)
  • 这是一个全面的答案。做得好。不过有一点需要注意,在`img.addEventListener("error", err =&gt; reject(err));` 中不需要箭头函数,`img.addEventListener("error", reject);` 就足够了。 (3认同)

joe*_*joe 7

一个压缩/简短的例子:

let url = "https://example.com/image.png";
let img = new Image();
await new Promise(r => {img.onload=r; img.src=url});
// now do something with img
Run Code Online (Sandbox Code Playgroud)