小程序开发(四)使用promise处理异步流程

背景

在小程序中,我们会经常使用官方提供的API,但是大多数API是异步执行的。
例如,微信获取用户地理位置的API:

wx.getLocation({
  type: 'wgs84',
  success: (res) => {
    var latitude = res.latitude // 经度
    var longitude = res.longitude // 纬度
  }
})

可以看到,success事件是以异步回调的形式执行的。当获取用户地理位置成功时,才会执行 success 事件。

大量的异步回调,会形成回调地狱,导致代码难以维护。例如,下面是小程序内登录的一段逻辑:

wx.login({
  success: (res) => {
    const { code } = res;

    wx.getUserInfo({
      success: (res) => {
        const { userInfo } = res;

        wx.request({
          method: 'POST',
          url : '服务端的登录接口',
          data: {
            code,
            userInfo,
          },
          success: (res) => {
            if (res.statusCode === 200) {
              const token = res.data.token;
              console.log('登录成功');
            }
          },
          fail: (res) => {
            console.log('异常...')
          },
        })
      }
    })
  }
})

简单的描述一下这段代码的逻辑:

  1. 调用wx.login,获取 code
  2. 调用wx.getUserInfo,获取 userInfo
  3. 调用wx.request,将codeuserInfo发送给服务器,获取登录token

在这段代码里面,尽管我们省略了大量的异常处理,仍进行了3次嵌套。当遇到复杂的业务时,嵌套的层级会更深,代码将变得异常难维护。

使用Promise简化代码

我们使用Promisewx.login包一层,这样我们就可以链式调用。避免回调嵌套。

const wx_login = () => {
  return new Promise((resolve, reject) => {
    wx.login({
      success: (res) => {
        resolve(res);
      },
      fail: (err) => {
        reject(err);
      }
    })
  });
};

wx_login().then((res) => {
    const { code } = res;
  })
  .catch((err) => {
    console.log(err);
  });

通用 Promise 化API方法

由于小程序的异步API都是success和fail的形式,所以,我们可以封装一个通用的Promise化得方法

// 原文地址:https://segmentfault.com/a/1190000013150196
// promisify.js
module.exports = (api) => {
  return (option, ...params) => {
    return new Promise((resolve, reject) => {
      api(Object.assign({}, option, { success: resolve, fail: reject }), ...params);
    });
  }
};
const promisify = require('./promisify');
const wx_login = promisify(wx.login);

wx_login().then((res) => {
  const { code } = res;
});

使用promisify改进登录的代码

const promisify = require('../../utils/promisify.js');
const get_userinfo = promisify(wx.getUserInfo);
const get_code = promisify(wx.login);
const wx_request = promisify(wx.request);
const HOST = 'https://api.xx.cn';

const login = () => {
  return Promise.all([get_userinfo(), get_code()])
    .then((results) => {
      const userinfo = results[0].userInfo;
      const code = results[1].code;

      return wx_request({
        url: `${HOST}/oauth`,
        method: 'POST',
        data: {
          userinfo,
          code,
        },
      })
    }).then(res => {
      return res.data;
    });
};

login().then((res) => {
  const { token } = res;
})

总结

异步编程的最高境界,就是根本不用关心它是不是异步。

使用Promise处理异步流程,帮助我们简化了代码逻辑,避免了层层嵌套的回调,让代码更容易维护。

但是,面条式代码并不优雅,最好是能将async/await引入到小程序中。代码的逻辑会变得更加清晰,更容易维护。期待,高手指点。

参考资料

  • 小程序社区
  • 微信小程序:回调,Promise,async,await 的使用例子
  • 微信小程序中使用Promise进行异步流程处理
  • 微信小程序:使用Promise简化回调

你可能感兴趣的:(小程序开发(四)使用promise处理异步流程)