前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >es6异步方法在项目中的实践

es6异步方法在项目中的实践

作者头像
用户2845596
发布2021-01-21 15:14:05
3590
发布2021-01-21 15:14:05
举报
文章被收录于专栏:劝学劝学

es6异步方法在项目中的实践

author: teal.yao

polling

代码语言:javascript
复制
/// 轮询

// promise version
function fetchProtocol_promise(token) {
    let counter = 0;
    return new Promise((resolve, reject) => {
        polling();

        function polling() {
            fetch().then(() => {
                if (data.status === 200) {
                    switch (data.result.state) {
                        case 2:
                            resolve(getPreviewURL(data.result.url))
                            break
                        case 1:
                            if (counter++ > 20) {
                                reject("合同创建超时,请重新再试")
                            }
                            // fetch again
                            setTimeout(polling, 300)
                            break
                        case 3:
                            reject("合同创建失败")
                            break
                    }
                }
            })
        }
    });
}


/// async version
// 对比promise方式,会多了一个变量来管理状态成功
// 利用了promise里面的resolve接收的是一个promise,则会等待此promise的完成
async function fetch(token) {
    let counter = 0;
    return await polling();

    async function polling() {
        if (counter++ > 20) {
            return [false, "合同创建超时,请重新再试"]
        }
        let data = await fetch()
        if (data.status === 200) {
            switch (data.result.state) {
                case 2:
                    return [true, getPreviewURL(data.result.url)]
                case 1:
                    // fetch again
                    return new Promise(resolve =>
                        setTimeout(function () {
                            // waiting for polling state change
                            resolve(polling());
                        }, 300)
                    );
                case 3:
                    return [false, "合同创建失败"]
            }
        }
    }
}
复制代码

给promise设置timeout

代码语言:javascript
复制
/**
 * timeout promise
 * 
 * promise没有原生的超时的方法,得借用其他方法去处理
 * 
 * 1. promise的两个最终状态, fulfilled、 rejected
 * 
 * 2.下面借用Promise.race来处理超时
 * 
 * Promise.race(iterable),当iterable参数里的任意一个子promise被成功或失败后,
 * 父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,
 * 并返回该promise对象。
 */

/// https://italonascimento.github.io/applying-a-timeout-to-your-promises/
const http = require('http')

let get = function (url) {
    return new Promise((resolve, reject) => {
        // 假装这里不支持timeout参数
        http.get({
            url,
        }, res => {
            res.on('data', d => {
                resolve(d.toString())
            })
        })
    })
}

/// promise timeout + promise.race
function promiseTimeout(promise, ms) {
    let timeout = new Promise((resolve, reject) => {
        setTimeout(function () {
            reject('timeout')
        }, ms)
    })
    return Promise.race([promise, timeout])
}
promiseTimeout(get('http://github.com'), 5).then(text => {
    console.log({
        text
    })
}).catch(err => {
    console.log({
        err
    })
})
复制代码

回调地狱的解决方案

代码语言:javascript
复制
  /**
   * ======解决回调地狱的=========
   *  
   * 常用的回调套回调,容易出现回调地狱,造成代码的可读性、维护性差
   * 
   * 现借助promise来解决
   */


  class Form {
      constructor(num, errMsg) {
          this.num = num
          this.errMsg = errMsg
      }
      validator(callback) {
          callback(this.num < .4)
      }
  }
  let form1 = new Form(.3, 'im .3')
  let form2 = new Form(.7, 'im .7')
  let form3 = new Form(.6, 'im .6')

  // 1. 回调地狱写法
  // 回调之后还是回调,无穷无尽
  form1.validator(valid => {
      if (valid) {
          form2.validator(valid => {
              if (valid) {
                  form3.validator(valid => {
                      if (valid) {
                          console.log({
                              valid
                          })
                      } else {
                          console.log({
                              err: form3.errMsg
                          })
                      }
                  })
              } else {
                  console.log({
                      err: form2.errMsg
                  })
              }
          })
      } else {
          console.log({
              err: form1.errMsg
          })
      }
  })

  // 2. use async/await
  // 把callback包装成promise,结合await同步写法
  // 提高代码的可读性
  let formSerialValidator = async function (forms) {
      let valid = true
      let errMsg = ''
      // 用for来模拟表单的线性调用 
      for (let form of forms) {
          // 利用await的同步写法
          // 接收promise的resolve传值,或reject的传值
          // 保持 resolve/reject 传值结构是一样的: tuple [boolean, string]
          [valid, errMsg] = await promiseFactory(form)
          //   .catch(errMsg => {
          //       // 保持与resolve返回结果一致
          //       return [false, errMsg]
          //   })
          if (!valid) {
              break
          }
      }
      return [valid, errMsg]

      // 将回调包装成promise
      function promiseFactory(form) {
          return new Promise((resolve, reject) => {
              form.validator(valid => {
                  //   if (valid) {
                  resolve([valid, form.errMsg])
                  //   }
                  //   reject(form.errMsg)
              })
          })
      }
  }
  formSerialValidator([form1, form2, form3]).then(([valid, errMsg]) => {
      console.log({
          valid,
          errMsg
      })
  })


  // 3. promise + reduce
  // 利用then的链式调用
  // a().then(() => new Promise()).then(() => new Promise())  第一个then为reject时,整个链的状态就是reject
  let reduceValidator = function (forms) {
      // 用reduce生成校验的Promise chain

      // reduce的初始initValue得注意下,是Promise.resolve()
      // Promise.resolve()传递的是一个具体的值(undefined),所以状态为fulfilled,可直接使用then调用
      // Promise then方法返回的promise,则等待该promise的返回
      return forms.reduce((promise, form) => {
          return promise.then($ => {
              return new Promise((resolve, reject) => {
                  form.validator(valid => {
                      console.log(valid)
                      // resolve 只能有一个参数
                      if (valid) {
                          resolve(true)
                      }
                      reject(form.errMsg)
                  })
              })
          })
      }, Promise.resolve())
  }
  reduceValidator([form1, form2, form3]).then(valid => {
      console.log({
          valid,
      })
  }).catch(errMsg => {
      console.log({
          errMsg
      })
  })

  // Promise then方法返回的promise,则等待该promise的返回
  Promise.resolve(new Promise((resolve, reject) => {
      resolve(1)
  })).then(res => {
      console.log(res)
  })
复制代码

表单验证的yield写法

代码语言:javascript
复制
 /// 传统表单的校验

 // 一般人的写法
 // this.$message.error重复调用,不利于维护
 function validator1() {
     let msg = ''
     if (fd.displayPosition === null) {
         this.$message.error('请选择发送端')
         //  return false
     } else if (fd.type === null) {
         this.$message.error('请选择通知方式')
         //  return false
     } else if (fd.peroid === undefined || JSON.stringify(fd.peroid) === '[null,null]') {
         this.$message.error('请选择有效日期')
         //  return false
     } else if (self.isShowNum && fd.showNum === null) {
         msg = '请选择弹出次数'
         //  return false
     }
     this.$message.error(msg)
     return true
 }

 // 二般人的写法
 // 利用yield给暂停一下
 // generator函数调用后生成一个Iterator对象,返回的done为true时结束
 // Iterator: {
 //    next() {
 //         return {
 //             value: any,
 //             done: boolean
 //         }
 //     }
 // }
 //
 // for..of 实现了Iterator接口,可以调用generator函数的生成对象
 function validator2() {
     function* check() {
         if (fd.displayPosition === null) {
             yield '请选择发送端'
         }
         if (fd.type === null) {
             yield '请选择通知方式'
         }
         if (fd.peroid === undefined || JSON.stringify(fd.peroid) === '[null,null]') {
             yield '请选择有效日期'
         }
         if (self.isShowNum && fd.showNum === null) {
             yield '请选择弹出次数'
         }
     }
     let iterator = check()
     for (let msg of iterator) {
         //  if (msg !== undefined) {
         this.$message.error(msg)
         return false
         //  }
     }
     return true
 }
复制代码

代码片段的复用

如下面的代码所示,执行Success代码条件有两处,在上面的写法里,这两处分开书写,代码没有复用 利用promise的resolve就可以复用了,如第二个例子所示

代码语言:javascript
复制
if (condition1) {
    promise().then(() => {
        // do Success code here
    }).catch(() => {
        // do Fail code here
    })
} else {
    // do Success code here
}
复制代码
代码语言:javascript
复制
new Promise((resolve, reject) => {
    if (condition1) {
        promise().then(resolve).catch(reject)
    } else {
        resolve()
    }
}).then(() => {
    // do Success code here
}).catch(() => {
    // do Fail code here
})
复制代码

promise/async的错误处理

代码语言:javascript
复制
/// 1. promise内部的错误,不会中断外部的执行
new Promise((resolve, reject) => {
    throw Error('promise')
    console.log(1)
})
console.log('after promise error')
// 可使用try-catch或Promise.prototype.catch处理
new Promise((resolve, reject) => {
    try {
        throw Error('promise')
    } catch (err) {
        console.log(err)
    }
})
console.log('after promise error')

// 与上面的捕获错误的方法对比,throw Error后面的代码将无法执行
new Promise((resolve, reject) => {
        throw Error('promise')
        console.log('after inner error')
    })
    .catch(err => {
        console.log(err)
        // return 'form catch'
        throw Error('from catch')
    })
    .catch(res => {
        console.log(res)
    })

console.log('after promise error')


/// 2. async函数的错误处理
// 处理await返回的错误,promise不捕获,则留给async函数处理
// promise前面加await与不加的区别
// 观察下面3种情况:
// 1. 内部promise错误不处理
// 2. 内部promise加上catch
// 3. 内部promise接上await 
async function usePromiseCatch() {
    new Promise((resolve, reject) => {
        throw Error('throw')
        console.log(330)
    })
    // .catch(err => {
    //     console.log(err)
    // })
    console.log('continue')
}

usePromiseCatch().catch(err => {
    console.log('in async catch', err)
})
复制代码
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • es6异步方法在项目中的实践
    • polling
      • 给promise设置timeout
        • 回调地狱的解决方案
          • 表单验证的yield写法
            • 代码片段的复用
              • promise/async的错误处理
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档