• 学习笔记—Promise的静态方法(原型方法)


    日常的学习笔记,包括 ES6、Promise、Node.js、Webpack、http 原理、Vue 全家桶,后续可能还会继续更新 Typescript、Vue3 和 常见的面试题 等等。

    Promise静态方法

    这篇文章只记录实现,不记录用法。

    之前我们封装了一个符合 promise/A+ 规范的类库 Promise,那现在我们来实现一下类库中包含的静态方法。

    Promise.resolve()

    Promise.resolve(100) 等价于 new Promise((resolve,reject)=>{resolve(100)})

    实现此方法非常简单,在我们实现好的类库中添加静态方法。

    static resolve(val) {
      return new Promise((resolve, reject) => {
        resolve(val)
      })
    }
    

    Promise.reject()

    Promise.reject(100) 等价于 new Promise((resolve,reject)=>{reject(100)})

    实现此方法也非常简单,在我们实现好的类库中添加静态方法。

    static reject(val) {
      return new Promise((resolve, reject) => {
        reject(val)
      })
    }
    

    Promise.catch()

    Promise.catch() 等价于 .then(null, () => {})

    所以我们可以直接在类库中实现此方法

    catch (errorFn) {
      return this.then(null, errorFn)
    }
    

    Promise.all()

    现有如下代码

    let promise1 = new Promise((resolve, reject) => {resolve(100)})
    let promise2 = new Promise((resolve, reject) => {reject(200)})
    let promise3 = new Promise((resolve, reject) => {resolve(300)})
    let promise4 = new Promise((resolve, reject) => {resolve(400)})
    Promise.all([promise1, promise2, promise3, promise4]).then(result => {
      console.log(result);
    }).catch(reason => {
      console.log(reason); // 200
    })
    

    有多个Promise实例,当所有的实例都执行完毕后,才会执行其成功结果。当其中有一个实例失败了,整个Promise.all的结果都会变成失败

    根据上述结论,我们可以试着实现Promise.all()

    static all(promises) {
      return new Promise((resolve, reject) => {
        let results = []
        let times = 0
        const processSuccess = (index, val) => {
          results[index] = val;
          if (++times === promises.length) {
            resolve(results)
          }
        }
        for (let i = 0; i < promises.length; i++) {
          let p = promises[i];
          if (p && typeof p.then === 'function') {
            p.then(result => {
              processSuccess(i, result)
            }, reject)
          } else {
            processSuccess(i, p)
          }
        }
      })
    }
    

    Promise.race()

    有多个Promise实例,最先执行完成的实例返回结果后,整个Promise.race 就执行完毕了。

    static race(promises) {
      return new Promise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
          let p = promises[i]
          if (p && typeof p.then === 'function') {
            p.then(resolve, reject)
          } else {
            resolve(p)
          }
        }
      })
    }
    

    实际案例

    实际工作中,Promise.race() 可以用来处理 图片加载失败 或者 脚本加载超时 等问题。

    function wrap(p1) {
      let abort;
      let p = new Promise((resolve, reject) => {
        abort = reject;
      })
      let p2 = Promise.race([p, p1]); // 将自定义的错误Promise和自己设定的Promise组合
      p2.abort = abort;
      return p2;
    }
    // 使用
    let p1 = new Promise( ... ) // 需要处理的Promise异步操作
    let promise = wrap(p1);
    promise.then(result=>{ ... },reason=>{ ... }) // 成功或失败的回调
    // 超时处理
    setTimeout(() => {
      promise.abort(); // 设定超时时间为60s
    }, 60000);
    

    封装一个wrap() 函数,接受参数是 Promise 数组。在函数内设定一个属性值 abortabort 获取值一个新的Promise中的reject方法。

    这样wrap函数中的abort就相当于一个中断按钮。

    Promise.finally()

    无论Promise成功还是失败,都会执行此方法,他不会接受上一层 .then 方法传递的参数。

    执行过后,代码会继续执行(后续的 .then 方法会继续执行),如果在.finally() 中返回一个新的 Promise,Promise除了失败结果,任何结果都不会被传递下去。

    finally(onFinally) {
      return this.then(
        // Promise.resolve 可以等待回调中的Promise执行完毕
        value => Promise.resolve(onFinally()).then(() => value),
        reason => Promise.resolve(onFinally()).then(() => {
          throw reason
        })
      )
    }
    

    Promise.allSettled

    有多个Promise实例,当所有的实例都执行完毕后,会将所有结果全部返回,无论结果是正确还是错误的。所以他不会走.catch方法。

    Promise.any

    有多个Promise实例,如果其中有一个成功了,就会走其成功结果取出第一个成功的值),只有全部失败了,才会走失败结果

    promisify

    我在上一篇文章中,曾经封装过一个 Promise 的异步函数 readFile ,当时用了一种很麻烦的封装方式。

    const fs = require('fs');
    function readFile(path, encoding) {
      return new Promise((resolve, reject) => {
        fs.readFile(path, encoding, (err, data) => {
          if (err) reject(err)
          resolve(data)
        })
      })
    }
    readFile('./a.txt', 'utf8').then(result => { console.log(result) })
    

    那我们有没有什么简单的方法可以使用呢?答案是 有的。

    Node中内置模块 util 中有一个 promisify 方法,可以神奇的将 异步函数 转换成 Promise。

    const fs = require('fs');
    const util = require('util');
    let readFile = util.promisify(fs.readFile) // 省略了自己的封装过程
    readFile('./a.txt', 'utf8').then(result => { console.log(result) })
    

    现在我们可以尝试自己手写一下其 实现原理

    function promisify(readFile) {
      return function (...args) {
        return new Promise((resolve, reject) => {
          readFile(...args, (err, data) => {
            if (err) return reject(err)
            resolve(data)
          })
        })
      }
    }
    

    这样我们就手写了一个 promisify 方法。

    本篇文章由莫小尚创作,文章中如有任何问题和纰漏,欢迎您的指正与交流。
    您也可以关注我的 个人站点博客园掘金,我会在文章产出后同步上传到这些平台上。
    最后感谢您的支持!

  • 相关阅读:
    懒加载——实现原理
    html5shiv.js和respond.min.js
    点击app分享链接,js判断手机是否安装某款app,有就尝试打开,没有就下载
    ajax获取后台数据渲染(整片文章不分段落)解决方案,要使用htmL方式输出
    +-下拉菜单
    html 中a标签的问题(无反应,跳转,调用方法)
    js中两种定时器,setTimeout和setInterval的区别
    chrome 调试进入 paused in debugger 状态解决办法
    mybatis-plus 获取新增id
    linux unzip和zip
  • 原文地址:https://www.cnblogs.com/moxiaoshang/p/15101535.html
Copyright © 2020-2023  润新知