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

时间:2018-08-28 13:53:56

标签: javascript html5-canvas es6-promise

我正在尝试从here了解如何用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. 
/
});

编辑

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

image.addEventListener('load', () => {
                resolve(image);

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

image.scr = url;

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

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

编辑2:

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

1 个答案:

答案 0 :(得分:6)

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

在这种情况下,您需要一个Image已完全加载并具有可使用的图像数据。但是,在网络请求完成之前,您无法访问该图像数据,而网络请求会提取该图像数据。

例如,这将不起作用:

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

相反,我们必须等待,直到加载完成。有很多方法可以做到这一点,但是最常见的约定是使用,回调,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);
});


老实说,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));