【问题标题】:async await in image loading图像加载中的异步等待
【发布时间】:2018-03-06 01:40:45
【问题描述】:

Temp.js

export default class Temp {
    async addImageProcess(src){
        let img = new Image();
        img.src = src;
        return img.onload = await function(){
          return this.height;
        }
    }
}

另一个文件.js

import Temp from '../../classes/Temp'
let tmp = new Temp()

imageUrl ="https://www.google.co.in/images/branding/googlelogo/2x/googlelogo_color_120x44dp.png"
let image = tmp.addImageProcess(imageUrl);
console.log(image)

以上是我的代码。我有一个图像 url 并尝试使用 async await 获取图像的属性,但它不起作用,不明白我错过了什么。

【问题讨论】:

    标签: javascript ecmascript-6 async-await


    【解决方案1】:

    您的问题来自the definition for await...

    await 运算符用于等待Promise

    Image.prototype.onload 属性不是一个承诺,您也没有分配它。如果您想在加载后返回 height 属性,我会改为创建一个 Promise...

    addImageProcess(src){
      return new Promise((resolve, reject) => {
        let img = new Image()
        img.onload = () => resolve(img.height)
        img.onerror = reject
        img.src = src
      })
    }
    

    然后您将使用以下内容访问该值

    tmp.addImageProcess(imageUrl).then(height => {
      console.log(height)
    })
    

    或者,如果在 async 函数中

    async function logImageHeight(imageUrl) {
      console.log('height', await tmp.addImageProcess(imageUrl))
    }
    

    【讨论】:

    • 谢谢@phil,现在我明白了。 addImageProcess 中有一个小错字。
    【解决方案2】:

    以前的答案是正确的,但我想指出现在有一个 HTMLImageElement.decode() 方法几乎对应于 Promisified onload 处理程序。

    这样做的好处是不需要自己包装,处理已经加载的图像(以前的答案在这种情况下失败),并等待图像被实际解码,这在各种情况下可能是一件好事(例如,如果您想将它与同步 Canvas2DContext.drawImage() 方法一起使用,则在完成此解码时您的脚本将被阻塞)。

    所以现在只需要

    (async () => {
      const img = new Image();
      img.src = "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png";
      await img.decode();
      // img is ready to use
      console.log( `width: ${ img.width }, height: ${ img.height }` );
    })();

    【讨论】:

    • 其他答案可能是正确的,但这个答案干净优雅。
    • 这绝对是现代 Web 开发者的更好答案。
    • 谢谢!!!!!!!
    • 使用此功能的朋友请注意,decode() 与 IE 不兼容
    【解决方案3】:

    虽然建议的解决方案完美运行,但我希望能够避免为每个异步函数编写承诺,因此我为此编写了一个通用实用程序函数:

    在 JavaScript 中

    function onload2promise(obj){
        return new Promise((resolve, reject) => {
            obj.onload = () => resolve(obj);
            obj.onerror = reject;
        });
    }
    

    在打字稿中(包括一些通用类型检查):

    interface OnLoadAble {
       onload: any;
    }
    function onload2promise<T extends OnLoadAble>(obj: T): Promise<T> {
       return new Promise((resolve, reject) => {
       obj.onload = () => resolve(obj);
       obj.onerror = reject;
     });
    }
    

    在问题示例中,您现在可以这样做:

    async function addImageProcess(src){
        let img = new Image();
        let imgpromise = onload2promise(img); // see comment of T S why you should do it this way.
        img.src = src;
        await imgpromise;
        return this.height;
    }
    

    当然,anotherfile.js 中的调用也应该异步发生,如 Phils 回答的最后一个代码块中所述

    【讨论】:

    • 承诺从不拒绝。设置onerror:function onload2promise(obj){ return new Promise((resolve,reject) =&gt; { obj.onload = () =&gt; resolve(obj); obj.onerror = reject; }); }
    • 你的方法有点危险:它在图像加载开始后设置onload。见stackoverflow.com/questions/14648598/…
    • 好话,我想我更新了答案以解决您提到的问题!
    • 不错!更多想法:onabort 是否也应该拒绝 Promise? interface OnLoadAble 应该包含onerror(如果添加为拒绝事件,则onabort)。在您上一个代码块中,您的意思是 return img.height;
    猜你喜欢
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 2020-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-22
    相关资源
    最近更新 更多