javascript 异步请求封装成同步请求

 

        此方法是异步请求封装成同步请求,加上token验证,环境试用微信小程序,可以修改文件中的ajax,进行封装自己的,比如用axios等

       成功码采用标准的 200 到 300 和304 ,需要可以自行修改

       同步任务接入之后,每个任务会进行token的验证,每个任务之间都是同步请求,包括token

/**
 *  同步流请求
 *  token验证每个接口
 *  柯里化添加同步任务
 *  resolve返回res,cb
 *  reject 返回res,cb
 *  通过任务中断测试
 *  通过成功失败回调函数测试
 * 
 *  任务流 任务接入柯里化函数 currying(()=>{})              -->
 *  开始执行 currying() 进入g函数循环同步执行异步方法        -->
 *  执行异步方法 调用 rp 函数 封装 return new promise       -->
 *  rp 函数 执行判断 token 状态 进行处理
 */


const regeneratorRuntime = require('./regenerator-runtime/runtime.js') //runtime类
const errorMessage = '服务繁忙,稍后再试' //公共提示
const successMessage = '完成' //公共提示

class SuperClass {
  constructor() {
    Object.assign(this, {})
    //等待执行的接口
    this.wait = []
  }

  //Promise 请求接口
  rp(opts, skipToken = false) {
    const _t = this,
      data = opts.data || {}
    //小程序标识
    data.source = opts.sourceFlag ? data.source : 1;

    //请求信息
    console.group(`请求接口---${opts.url}`);
    console.log('接口信息', {
      opts,
      skipToken
    })
    console.groupEnd();

    return new Promise(function(resolve, reject) {

      opts.header = {
        "Content-Type": "application/json;charset=utf-8",
        //不需要走token的接口
        Authorization: !!opts.skipToken ? '' : (wx.getStorageSync('token') || '')
      }

      wx.request({
        url: '域名' + opts.url,
        data: data,
        header: opts.header,
        method: opts.method,
        dataType: 'json',
        responseType: 'text',
        success: function(res) {
          const {
            data
          } = res

          //成功 400为token失效 处理token失效问题 内层函数收集token失败码归并处理 
          if (data && (_t.successCode({
              code: data.code
            }) || data.code == 400)) {
            resolve(data)
          } else {
            //其他不可预测为失败
            reject(data)
          }
        },
        fail: function(res) {
          reject(res.data)
        },
        complete: function(res) {
          //完成停止加载 
          wx.hideToast()
          opts.complete && opts.complete(res.data)
        }
      })
    })
  }

  //为空参数抛异常
  paramNoNull() {
    throw new Error('Missing parameter')
  }

  // g函数
  async g() {
    let _t = this,
      //中断任务
      isbreak = !1

    for (let [i, v] of _t.wait.entries()) {
      const r = await v().catch((res) => {
        //收集 所有的错误 统一执行 提示 或者错误回调
        const {
          cb,
          message
        } = res

        //同步流中断
        _t.clearWait()
        isbreak = !0;
        //没有回调函数执行错误提示
        'cb' in res ? cb() : (wx.factory._toast(message || errorMessage))
      })

      //任务执行成功
      if (!!r && r.constructor === Object && !!Object.keys(r).length) {
        const {
          res: {
            code,
            data,
            message
          },
          cb
        } = r

        //外层函数只处理成功状态
        if (_t.successCode({
            code
          })) {
          !!cb && cb()

          //同步流执行完成
          if ((i + 1) == _t.wait.length) {
            _t.clearWait()
            wx.factory._toast(message || successMessage)
          }
        } else {
          //同步流中断
          _t.clearWait()
          isbreak = !0

          wx.factory._toast(message || errorMessage)
        }
      }

      if (!!isbreak) {
        break
      }
    }
  }

  //清空任务
  clearWait() {
    this.wait = []
  }

  //柯里化
  currying() {
    const _t = this
    return (function(arg) {
      if (arg.length === 0) {
        _t.g()
      } else {
        [].push.apply(_t.wait, arg);
      }
    })(arguments)
  }

  //成功码
  successCode({
    code = 404
  }) {
    return (code >= 200 && code < 300) || code == 304
  }
}

//超类,实现多继承
const decorator = Sup => class extends Sup {
  constructor(...args) {
    super(...args)
  }

  //获取token接口
  greatetoken(opts) {
    let codeOPts = JSON.parse(JSON.stringify(opts));
    codeOPts.url = `/getToken`
    codeOPts.method = `POST`
    codeOPts.data = {
      appIds: "xx",
      userId: 5
    }
    return super.rp(codeOPts, true).then((res) => {
      const {
        code,
        data
      } = res
      if (super.successCode({
          code: cb.code
        })) {
        if (!!data && !!data.token) {
          //全局token存储 方式为 storage
          wx.setStorageSync('token', data.token)
        } else {
          wx.factory._toast('获取token失败')
        }
      } else {
        wx.factory._toast('获取token失败')
      }
    }).catch(() => {
      wx.factory._toast('获取token失败')
    })
  }

  /**
   * 接口公共类 
   * 同步请求返回 Promise
   * 请求 token 为前提,为空 过期重新请求
   */
  async send(opts) {
    const token = wx.getStorageSync('token'),
      sendFun = (opts) => {

        //转化http请求 catch捕获promise的reject 展示接口级别错误 只做console打印 其他操作流入g函数(回调,提示)
        return super.rp(opts).catch(res => {

          //此处显示rp reject 报错
          console.group(`%c请求接口---${opts.url}---报错`, 'color:red;');
          console.log(` --> 参数`, {
            data: opts.data
          });
          console.log(` --> 返回值`, {
            res
          });
          console.groupEnd();

          //把错误信息传到 g 函数的catch里面
          opts.fail && opts.fail(res)
        })
      },
      successFun = async(opts) => {
        const cb = await sendFun(opts)

        //把成功信息传到g函数里面
        super.successCode({
          code: cb.code
        }) && opts.success && opts.success(cb)
      }


    if (!opts.skipToken) { //需要token请求
      if (!token) { //token为空 直接发起token请求
        await this.greatetoken(opts)
        await successFun(opts)
      } else {
        const cb = await sendFun(opts)
        if (!!cb) {

          //400 token过期  只有在存在token的情况下才会有时效的情况 归并处理
          if (cb.code == 400) {
            await this.greatetoken(opts)
            await successFun(opts)
          } else {
            //把成功信息传到g函数里面
            super.successCode({
              code: cb.code
            }) && opts.success && opts.success(cb)
          }
        }
      }
    } else {
      await successFun(opts)
    }
  }

  post(opts) {
    opts.method = "POST";
    this.send(opts)
  }

  get(opts) {
    opts.method = "GET";
    this.send(opts);
  }
}

class Http extends decorator(SuperClass) { //子类
  constructor() { //继承参数
    super()
  }
}

export default new Http

 

    引入方式,全局调用

import Http from './public/js/request'
wx.http = Http

 

    调用执行,可用bind函数进行传参

    success返回为成功的,code值流入任务进行code值判断区分 resolve

    fail返回失败 reject

    complete执行的为方法

 

Page({
   onLoad(){
     wx.http.currying(this.a.bind(this, {
      a: 1
    }))
    //进行传参bind
    wx.http.currying(this.b)
    wx.http.currying()
  },
  a() {
    const _t = this
    wx.factory._toast('加载a信息中...', 6000)
    return new Promise((resolve, reject) => {
      wx.http.post({
        url: 'a',
        data: {
          "params": {
            id:33
          }
        },
        success(res) {
          resolve({
            res,
cb()=>{} }) }, fail(res) { reject({ res,
cb()=>{} }) } }) }) }, b() { const _t
= this wx.factory._toast('加载b信息中...', 6000) return new Promise((resolve, reject) => { wx.http.post({ url: 'b', data: { id:33 }, success(res) { resolve({ res }) }, fail(res) { reject({ res }) } }) }) } })

 

posted @ 2019-08-08 20:35  两面一汤  阅读(3157)  评论(0编辑  收藏  举报