乐趣区

记一次小程序开发中如何使用async-await并封装公共异步请求

前言
在平常的项目开发中肯定会遇到同步异步执行的问题,还有的就是当执行某一个操作依赖上一个执行所返回的结果,那么这个时候你会如何解决这个问题呢;
1. 是用 settimeout 让它异步执行,显然这只是让它加入异步任务队列中去执行,但并不能保证等待其返回结果再去执行另一个操作。

2. 还是自己封装 callback 函数?那样就会陷入所谓的回调地狱,代码层层嵌套,环环相扣,逻辑稍微复杂就会很难去维护。

3. 当然 es6 中的 promise 倒是很好的解决了这样的问题,再配合 es7 的 async 和 await 就更完美了,await 返回的也是一个 promise 对象,这个关于 promise 和 async,await 的使用方法就不说了。

实现方案
首先小程序目前还是不支持 es7 的 async 和 await 的,那么如何让它支持呢

1、下载 [regenerator][1] 并把下载好的 runtime.js 文件夹放到自己小程序的 utils 目录下,包总共才 20kb 多,体积很小的。

![图片描述][2]

2、在需要调的地方引入 import regeneratorRuntime from ‘../../utils/runtime.js’

3、如何封装并使用

封装:

const postData = async function(url, data) {
wx.showLoading({
title: ‘ 加载中 ’,
})
let promiseP = await new Promise(function(resolve, reject) {
wx.request({
url: baseUrl + url,
data: data,
method: ‘POST’,
header: {
‘content-type’: ‘application/json’,
‘access-token’: wx.getStorageSync(‘token’)
},
success: function(res) {
wx.hideLoading();
if (res.statusCode === 200) {
resolve(res)
} else {
reject(res.data)
}
},
fail: function(err) {
wx.hideLoading();
reject(err)
if (err.code === 401) {}
}
})
})
return promiseP
}
module.exports = {
postData
}

使用:
import regeneratorRuntime from ‘../../utils/runtime.js’;
const app = getApp(),
postData = require(‘../../service/koalaApi.js’);

async demo() {
await postData(app.globalData.baseUrl + ‘/test’,{
data: {}
}).then((res) => {
console.log(res)
})
}
下面进行了更完善的一个封装,包括各种错误判断的处理和简化,通过传参的方式,来灵活调用
// 当前 host
const url_host = require(‘API.js’).host
// 当前版本
const currentVersion = require(‘util.js’).currentVersion
// 当前路径
import {currentPagePath} from ‘util.js’

// 调用 fetch 方法,然后依次链式传入
// url, method, header, data, loading(是否显示 loading)

function fetch(url, method, header, data, loading) {
// 判断给服务端传递 undefined 的问题
let fetchP = new Promise(function (resolve, reject) {
if (loading) {
wx.showLoading({
icon: ‘loading’
})
}
if(data && data.unionId && typeof data.unionId === “undefined”){
wx.hideLoading()
return reject({
ok:false,
error: ‘unionId -> ‘ + typeof data.unionId
});
}
wx.request({
url: url_host + url,
method: method ? method : ‘GET’,
header: {
‘content-type’: ‘application/json’, // 默认值
‘version’: currentVersion,
‘pagePath’: currentPagePath()
},
data: data,
success: function (res) {
if (res.statusCode < 500) {
resolve(res.data)
} else {
showError()
reject(res.data)
}
},
fail: function (err) {
showError()
reject(err)
},
complete: function (comp) {
if (loading) {
wx.hideLoading()
}
}
})
})
return fetchP
}

// 服务器开小差了
function showError () {
wx.hideLoading()
// 获取头文件路径
wx.navigateTo({
url: ‘/pages/serverError/serverError’,
})
}

module.exports = {
fetch
}
思考
1、为什么引入 regeneratorRuntime,就能够使用 async/await?不需要配合 babel 吗?
2、regeneratorRuntime 都做了什么?
总结
1、首先先明白 babel 和 polyfill 分别干啥的;
Babel 是一个广泛使用的转码器,Babel 默认只转换新的 JavaScript 句法,而不转换新的 API。

例如,Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转译。

如果想使用这些新的对象和方法,必须使用 babel-polyfill,为当前环境提供一个垫片。

2、Polyfill 用于实现浏览器并不支持的原生 API 的代码。
3、在明白上面的意思之后,还需要明白的是,babel-polyfill 是一股脑把全部都给你添加到 js 文件中,而现在的 runtime 将会判断你哪些需要加载的,有选择性的进行加载,并且后者也不会污染全局变量。在这里 regeneratorRuntime 最终转化成 es6 的 generator 来用的。具体的可以自己去下 babel 官网,输入相关代码可以看下最终转换后的代码。

退出移动版