在微信小程序项目中,接触到了promsie,参考其他文章,深入学习了promsie的原理及用法。学习异步编程。

在JavaScript的世界中,所有代码都是单线程执行的。

由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。

异步执行可以用回调函数实现:

1
2
3
4
5
6
function callback() {
console.log('Done');
}
console.log('before setTimeout()');
setTimeout(callback, 1000); // 1秒钟后调用callback函数
console.log('after setTimeout()');

观察上述代码执行,在Chrome的控制台输出可以看到:

1
2
3
4
before setTimeout()
after setTimeout()
(等待1秒后)
Done

可见,异步操作会在将来的某个时间点触发一个函数调用。

AJAX就是典型的异步操作。以上一节的代码为例:

1
2
3
4
5
6
7
8
9
request.onreadystatechange = function () {
if (request.readyState === 4) {
if (request.status === 200) {
return success(request.responseText);
} else {
return fail(request.status);
}
}
}

把回调函数success(request.responseText)fail(request.status)写到一个AJAX操作里很正常,但是不好看,而且不利于代码复用。

有没有更好的写法?比如写成这样:

1
2
3
var ajax = ajaxGet('http://...');
ajax.ifSuccess(success)
.ifFail(fail);

这种链式写法的好处在于,先统一执行AJAX逻辑,不关心如何处理结果,然后,根据结果是成功还是失败,在将来的某个时候调用success函数或fail函数。

古人云:“君子一诺千金”,这种“承诺将来会执行”的对象在JavaScript中称为Promise对象。

Promise有各种开源实现,在ES6中被统一规范,由浏览器直接支持。

我们先看一个最简单的Promise例子:生成一个0-2之间的随机数,如果小于1,则等待一段时间后返回成功,否则返回失败:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function test(resolve, reject) {
var timeOut = Math.random() * 2;
log('set timeout to: ' + timeOut + ' seconds.');
setTimeout(function () {
if (timeOut < 1) {
log('call resolve()...');
resolve('200 OK');
}
else {
log('call reject()...');
reject('timeout in ' + timeOut + ' seconds.');
}
}, timeOut * 1000);
}

这个test()函数有两个参数,这两个参数都是函数,如果执行成功,我们将调用resolve('200 OK'),如果执行失败,我们将调用reject('timeout in ' + timeOut + ' seconds.')。可以看出,test()函数只关心自身的逻辑,并不关心具体的resolvereject将如何处理结果。

有了执行函数,我们就可以用一个Promise对象来执行它,并在将来某个时刻获得成功或失败的结果:

1
2
3
4
5
6
7
var p1 = new Promise(test);
var p2 = p1.then(function (result) {
console.log('成功:' + result);
});
var p3 = p2.catch(function (reason) {
console.log('失败:' + reason);
});

变量p1是一个Promise对象,它负责执行test函数。由于test函数在内部是异步执行的,当test函数执行成功时,我们告诉Promise对象:

1
2
3
4
// 如果成功,执行这个函数:
p1.then(function (result) {
console.log('成功:' + result);
});

test函数执行失败时,我们告诉Promise对象:

1
2
3
p2.catch(function (reason) {
console.log('失败:' + reason);
});

Promise对象可以串联起来,所以上述代码可以简化为:

1
2
3
4
5
new Promise(test).then(function (result) {
console.log('成功:' + result);
}).catch(function (reason) {
console.log('失败:' + reason);
});

async await

async/await 可以同样逻辑的代码看起来舒服得多

1
2
3
4
5
6
(async () => {
const p = await new Promise(resolve => {
setTimeout(() => resolve("hello async/await"), 1000);
});
console.log(p);
})();

微信小程序中Api请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function openApi(deviceId, unionId) {
return new Promise(async (solve, reject) => {
wx.request({
url: `${host}/mini_program/api`,
header: {
'content-type': 'application/json' ,
},
method: 'POST',
data: {
device_id: deviceId,
union_id: unionId,
},
success (res) {
solve(res.data)
},
fail (res) {
reject(res)
}
})
})
}

参考资料

https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544

https://www.sunzhongwei.com/wechat-small-program-support-await-use-of-keyword

https://developers.weixin.qq.com/miniprogram/dev/framework/app-service/api.html#API

https://segmentfault.com/a/1190000021966277

http://t.zoukankan.com/sunzhao-p-8418796.html

https://blog.csdn.net/qq_41542894/article/details/123037302