1、获取异步函数(如网络请求wx.request({…})、wx.getSystemInfo({…})等)有success、fail回调函数的返回数据。
方法一:通过把this传出,来设置data中的hhOutPut的变量
方法二:把success改成箭头函数,格式success:(res)=>
修改后可以直接用this
Promise引入
1、假如异步函数中,如果依次要请求5次,第一次请求成功后才能请求第二次,第二次请求成功后才能请求第三次。以此类推,代码应该是这样写:
这样越写会越多,嵌套的代码也会增多。人们给它命名为:回调地狱
2、Promise就是基于解决这种回调地狱问题产生的,它可以让代码看起来更加扁平,也可以实现1中的获取异步函数的值。具体写法:
写一个Promise 回调函数
1、最简单的回调函数:把1中异步网络请求的代码改写成Promise回调函数
const promise = new Promise((resolve, reject) => {
//把需要异步处理的函数放在这里
wx.request({
url: 'https://294k1p5882.qicp.vip/hhtest.aspx',
data: {
keyword: InputStr,
keyword1: InputDataS
},
header: {
'content-type': 'application/json'
},
success: (res) => {
resolve(res)//成功的时候把成功的res用resolve传出
},
fail:(error)=> {
reject(error)//失败的时候把失败的error用reject传出
}
})
})
//这里处理异步运行完后的结果
promise.then((res) => {
//res一定要跟上面resolve(res)的对应,且顺序不能变,先res后error
this.setData({ hhOutPut: res.data })//在promise的处理结果中可以直接用this
}, (error) => {
//error一定要跟上面reject(error)对应,且顺序不能变,先res后error
})
2、假如箭头函数只有一个参数(res)的时候,res外面的括号可以去掉
假如箭头函数体你只有一方处理代码(resolves(res)),函数体的花括号也是可以去掉的
所以以上代码可以改写成这样:
const promise = new Promise((resolve, reject) => {
//把需要异步处理的函数放在这里
wx.request({
url: 'https://294k1p5882.qicp.vip/hhtest.aspx',
data: {
keyword: InputStr,
keyword1: InputDataS
},
header: {
'content-type': 'application/json'
},
success: res => resolve(res),//成功的时候把成功的res用resolve传出
fail: error => reject(error)//失败的时候把失败的error用reject传出
})
})
//这里处理异步运行完后的结果
promise.then(
res => this.setData({ hhOutPut: res.data }),//res一定要跟上面resolve(res)的对应,且顺序不能变,先res后error 在promise的处理结果中可以直接用this
error => console.log(error)
//error一定要跟上面reject(error)对应,且顺序不能变,先res后error
)
继续改进1:把Promise 作为函数返回
1、自定义异步请求函数
//自定义函数,返回Promise对象,传入网络请求的相关参数,可带默认参数路method
httpRequest(urlTemp,InputStrTemp, InputDataSTemp, method = 'GET') {
return new Promise((resolve, reject) => {
wx.request({
url: urlTemp,
data: {
keyword: InputStrTemp,
keyword1: InputDataSTemp
},
header: {
'content-type': 'application/json'
},
success: (res) => {
resolve(res)//成功的时候把成功的res用resolve传出
},
fail: (error) => {
reject(error)//失败的时候把失败的error用reject传出
}
})
})
},
2、调用:
BtnWeb: function (even) {
const Promise1 = this.httpRequest('https://294k1p5882.qicp.vip/hhtest.aspx', InputStr, InputDataS)
Promise1.then((res) => {
//res一定要跟上面resolve(res)的对应,且顺序不能变,先res后error
this.setData({ hhOutPut: res.data })//
}, (error) => {
//error一定要跟上面reject(error)对应,且顺序不能变,先res后error
})
},
3、在第一次调用成功后调用第二次,第二次成功后调用第三次
BtnWeb: function (even) {
//调用第一次
const Promise1 = this.httpRequest('https://294k1p5882.qicp.vip/hhtest.aspx', InputStr, InputDataS)
Promise1.then((res) => {
//第一次成功后调用第二次
const Promise2 = this.httpRequest('https://294k1p5882.qicp.vip/hhtest.aspx', InputStr, InputDataS)
Promise2.then((res) => {
//第二次成功后调用第三次
const Promise2 = this.httpRequest('https://294k1p5882.qicp.vip/hhtest.aspx', InputStr, InputDataS)
Promise2.then((res) => {
this.setData({ hhOutPut: res.data })//
}, (error) => {
})
}, (error) => {
})
}, (error) => {
})
},
4、虽然是可以调用成功,但是仍然没解决回调地狱问题
继续改进2: Promise真正解决回调地狱
1、调用方法
const Promise1 = this.httpRequest('https://294k1p5882.qicp.vip/hhtest.aspx', InputStr, InputDataS)
.then((res) => {
//第一次调成功的then下,调用第二次,用return返回Promise对象
return this.httpRequest('https://294k1p5882.qicp.vip/hhtest.aspx', InputStr, InputDataS)
}, (error) => {
})//以上的所有代码是调用2次后返回的Promise对象
.then((res) => {
//第二次调成功的then下,调用第三次,用return返回Promise对象
return this.httpRequest('https://294k1p5882.qicp.vip/hhtest.aspx', InputStr, InputDataS)
}, (error) => {
})//以上的所有代码是调用3次后返回的Promise对象
.then((res) => {
//第二次调成功的then下,修改页面数据
this.setData({ hhOutPut: res.data })
}, (error) => {
})
继续改进3: async/await的配合使用
1、原生的小程序并不支持async的使用:
2、到云盘下载支持文件
3、发到utils文件夹中,并在页面的js中引入
const regeneratorRuntime=require('../utils/runtime.js')
4、引入成功后,编译即可通过
5、添加需要异步处理的函数,若每个调用的都resolve,则发现输出结果跟我们要的一样
const regeneratorRuntime = require('../../utils/runtime.js')
Page({
data: {
},
BtnTest: function (even) {
this.TestAsync()
},
async TestAsync() {
try {
console.log('1开始');
let ret1 = await this.fun1(1)
console.log('1结束2开始');
let ret2 = await this.fun2(1)
console.log('2结束3开始');
let ret3 = await this.fun3(1)
console.log('3结束');
}
catch (e) {
console.log('---出错---', e);
}
},
fun1(flag) {
return new Promise((resolve, reject) => {
if (flag > 0) {
resolve('1-ok')
} else {
reject('1-ng')
}
})
},
fun2(flag) {
return new Promise((resolve, reject) => {
if (flag > 0) {
resolve('2-ok')
} else {
reject('2-ng')
}
})
},
fun3(flag) {
return new Promise((resolve, reject) => {
if (flag > 0) {
resolve('3-ok')
} else {
reject('3-ng')
}
})
}
})
6、假如第二个异步处理fun2时,reject结果。会发现:第三个不执行,调到catch报错
7、假如要在报错结果出做更复杂的逻辑处理可以这样做:
const regeneratorRuntime = require('../../utils/runtime.js')
Page({
data: {
},
BtnTest: function (even) {
let retAsync = this.TestAsync()
},
async TestAsync() {
try {
console.log('1开始');
let ret1 = await this.fun1(1).catch(err => Promise.reject("fun1异常"))
console.log('1结束2开始');
let ret2 = await this.fun2(-1).catch(err => Promise.reject("fun2异常"))
console.log('2结束3开始');
let ret3 = await this.fun3(1).catch(err => Promise.reject("fun3异常"))
console.log('3结束');
}
catch (e) {
switch (e) {
case "fun1异常":
console.log('---出错1---', e);
break;
case "fun2异常":
console.log('---出错2---', e);
break;
case "fun3异常":
console.log('---出错3---', e);
break;
}
}
},
fun1(flag) {
return new Promise((resolve, reject) => {
if (flag > 0) {
resolve('1-ok')
} else {
reject('1-ng')
}
})
},
fun2(flag) {
return new Promise((resolve, reject) => {
if (flag > 0) {
resolve('2-ok')
} else {
reject('2-ng')
}
})
},
fun3(flag) {
return new Promise((resolve, reject) => {
if (flag > 0) {
resolve('3-ok')
} else {
reject('3-ng')
}
})
}
})
继续改进3: async函数的返回值给调用方
BtnTest: function (even) {
this.TestAsync().then(function (res1) {
if (res1.indexOf("全部完成") >= 0) {
console.log(res1); //asyn函数全部执行成功并返回
} else {
console.log(res1); //asyn函数执行中间失败并返回
}
})
},
async TestAsync() {
try {
console.log('1开始');
let ret1 = await this.fun1(1).catch(err => Promise.reject("fun1异常"))
console.log('1结束2开始');
let ret2 = await this.fun2(-1).catch(err => Promise.reject("fun2异常"))
console.log('2结束3开始');
let ret3 = await this.fun3(1).catch(err => Promise.reject("fun3异常"))
console.log('3结束');
return "全部完成"
}
catch (e) {
switch (e) {
case "fun1异常":
console.log('---出错1---', e);
return "第1个出错了"
break;
case "fun2异常":
console.log('---出错2---', e);
return "第2个出错了"
break;
case "fun3异常":
console.log('---出错3---', e);
return "第3个出错了"
break;
}
}
},
循环async函数
BtnTest1: function (even) {
let aaa = this.xunhuan(1, 3) //调用循环,从第一次开始,总共要执行3次
},
xunhuan: function (currentIndex, AllCount) {
var that = this
that.TestAsync1(currentIndex).then(function (res1) {
if (res1.indexOf("整次成功") >= 0) {
if (currentIndex < AllCount) {
// 递归调用继续下一次
currentIndex = currentIndex + 1
that.xunhuan(currentIndex, AllCount)
} else {
return "全部完成"
}
} else {
console.log(res1);
return res1
}
})
},
//调用promis fun4和fun5
async TestAsync1(index) {
try {
console.log(index + '--4开始');
let ret1 = await this.fun4(1).catch(err => Promise.reject(index + "--fun4异常"))
console.log(index + '--4结束5开始');
let ret2 = await this.fun5(1).catch(err => Promise.reject(index + "--fun5异常"))
console.log(index + '--5结束');
return index + "--整次成功"
}
catch (e) {
switch (e) {
case index + "--fun4异常":
console.log(index + '---出错4---', e);
break;
case index + "--fun5异常":
console.log(index + '---出错5---', e);
break;
}
return index + "整次失败"
}
},
//定时2s后resolve或reject
fun4(flag) {
return new Promise((resolve, reject) => {
if (flag > 0) {
setTimeout(function () {
resolve('4-ok')
}, 2000);
} else {
setTimeout(function () {
reject('4-ng')
}, 2000);
}
})
},
//定时2s后resolve或reject
fun5(flag) {
return new Promise((resolve, reject) => {
if (flag > 0) {
setTimeout(function () {
resolve('5-ok')
}, 2000);
} else {
setTimeout(function () {
reject('5-ng')
}, 2000);
}
})
},
循环中使用Await
async TestAsync1() {
try {
console.log('--4开始');
let ret1 = await this.GetGameDataBase().catch(err => Promise.reject("GetGameDataBase异常"))
let Allne = ret1.data
let selectNe = []
for (const item of Allne) {
console.log('--4结束5开始', item.TouXianFileID);
let ret2 = await this.downloadTouXian(item.TouXianFileID).catch(err => Promise.reject("downloadTouXian异常"))
console.log('89', ret2)
}
//不用以下循环,否则会异步-----><<<<<<<<<<<<<<<<<<<<重点<<<<<<<<<<<<<<<<<
// Allne.forEach(async item => {
// console.log('--4结束5开始', item.TouXianFileID);
// let ret2 = await this.downloadTouXian(item.TouXianFileID) .catch(err => Promise.reject("downloadTouXian异常"))
// console.log('89', ret2)
// })
console.log('--5结束');
// return "--整次成功"
} catch (e) {
switch (e) {
case "GetGameDataBase异常":
console.log(e);
break;
case "downloadTouXian异常":
console.log(e);
break;
}
return "整次失败"
}
},
//定时2s后resolve或reject
GetGameDataBase() {
return new Promise((resolve, reject) => {
dbGameCollection.orderBy('Score', 'asc').get({
success: function (res) {
resolve(res)
},
fail: err => {
reject(err)
}
})
})
},
//定时2s后resolve或reject
downloadTouXian(TouXianFileID) {
return new Promise((resolve, reject) => {
wx.cloud.downloadFile({
fileID: TouXianFileID,
success: resTouXianFileID => {
resolve(resTouXianFileID)
},
fail: errTouXianFileID => {
reject(errTouXianFileID)
}
})
})
},