美文网首页
Promise 小记

Promise 小记

作者: Pober_Wong | 来源:发表于2018-04-01 19:43 被阅读28次

    这其实是一篇两年前实习所写 Gist 的中文说明,英文原档见这里

    先看看我写的烂代码

    async function checkImage (file, pixels) {
      const {width, height} = pixels
      return new Promise((resolve, reject) => {
        try {
          const img = await readImageFromFile(file)
    
          if (img.width !== WIDTH || img.height !== HEIGHT) {
            alert(`图标文件必须 ${pixels} 像素`)
          } else {
            resolve(img)
          }
        } catch (e) {
          reject(e)
        }
      })
    }
    

    这是一个检查图片尺寸的 Promise,主要流程就是使用 readImageFromFile 从文件对象中读取 image 对象,然后根据取出来的宽高来判断是否符合我们设定的要求,以此来确认是 resolve 还是 reject 这个 promise。整个流程还是比较简单的,但是依然还是由于对 Promise 了解的不够深入,导致写出了这样的代码。

    由于我们是要封装成 Promise 对象返回,所以在第一时间,我写出了 return new Promise 的代码,结果在构造 Promise 的时候,发现 readImageFromFile 这个方法也是一个将 Promise 作为返回值的 API,也就是说,作为异步的方法,我们要么使用如下:

    return Promise((resolve, reject) => {
      readImageFromFile(file)
        .then(img => {
          if (img.width !== WIDTH || img.height !== HEIGHT) {
            reject(`图标文件必须 ${pixels} 像素`)
          } else {
            resolve(img)
          }
      }).catch(e => reject(e))
    })
    

    要么就像原先的代码一样,使用 async-await 避免奇葩的 Promise 嵌套,但这样就需要使用 try-catch 来捕获异常了。

    看起来总让人感觉有点啰嗦,而这样的结果就是,我们需要使用这样来调用该方法:

    checkImage(...)
    .then()
    

    当然,如果你不使用 Promise 的话,则需要传入 onSuccess 和 onFailed 回调来解决问题了。

    代码的优化

    先讲点理论性的东西:
    async 修饰的异步方法本身就会返回一个 Promise 对象,其 return 的值会被作为 onResolve 的回调参数被传出,而 throw 抛出的异常,则会作为 onReject 的参数被传出。
    当然,你也可以把它当作普通方法来调用,不过这样的话,你是不能够从其返回值里拿到你想要的值的,因为它被作为 Promise 返回了,唯一的办法就是使用 回调来解决问题。

    接下来看看优化后的代码吧:

    async function checkImage (file, pixels) {
      const {width, height} = pixels
    
      try {
        const img = await readImageFromFile(file)
    
        if (img.width !== WIDTH || img.height !== HEIGHT) {
          alert(`图标文件必须 ${pixels} 像素`)
        } else {
          return img
        }
      } catch (e) {
        throw e
        alert('读取图片文件失败')
      }
    }
    

    和最原始代码的不同点就是我们去掉了手动封装的 Promise 对象,直接利用了 async-await 特性解决了问题,用法的话,依然和常规的 Promise 是一致的:

    let result = await checkImage(file, pixels)
    或者
    checkImage(file, pixels).then(result => normal, error => exception)
    

    结语

    整体看来,并没有什么难点,核心就是帮助我们解决 Promise 和 async-await 使用上的混淆问题。

    相关文章

      网友评论

          本文标题:Promise 小记

          本文链接:https://www.haomeiwen.com/subject/pjxacftx.html