【小程序】007 Promise与Async/Await
【摘要】 Promise 是一个 ECMAScript 6 提供的类,Async/await 是 ECMAScript 7 新增的内容,两者目的都是为了更加优雅地书写复杂的异步任务。此处介绍她们关于后面小程序开发所需要主要内容,更为详细内容请参考手册、文档。我们都知道JS是一个单线程的语言,一次只能执行一个任务,如果碰到时间较长任务,会被拖到任务队列等待其他任务完成后再执行。但是类似于向后台请求数据操...
Promise 是一个 ECMAScript 6 提供的类,
Async/await 是 ECMAScript 7 新增的内容,
两者目的都是为了更加优雅地书写复杂的异步任务。
此处介绍她们关于后面小程序开发所需要主要内容,更为详细内容请参考手册、文档。
我们都知道JS是一个单线程的语言,一次只能执行一个任务,如果碰到时间较长任务,会被拖到任务队列等待其他任务完成后再执行。但是类似于向后台请求数据操作,后面的数据处理任务依赖于请求数据的完整性,由于网络情况、服务端数据处理能力,数据包大小,可能并未得到完整数据就执行了后面的数据处理任务,出现意想不到的结果。为了保证数据获取的完整性,有必要使用异步操作。
回调地狱
如果需要多次调用异步函数,例如,如果我想分三次输出字符串,第一次间隔 1 秒,第二次间隔 2 秒,第三次间隔 3 秒:
setTimeout(function () {
console.log("First");
setTimeout(function () {
console.log("Second");
setTimeout(function () {
console.log("Third");
}, 3000);
}, 2000);
}, 1000);
如果调用嵌套的增加,代码层次变得更深,无论是维护还是异常处理难度也随之增加,尤其是我们使用的是可能包含了很多循环和条件语句的真实代码。这些容易使人迷茫的异步回调编写方式被称为“回调地狱”或“厄运金字塔”。
而Promise可以通过使每个行为都成为一个独立的函数来尝试减轻这种问题
Promise
Promise 对象的构造器(constructor)语法如下:
let promise = new Promise(function(resolve, reject) {
// executor
});
传递给 new Promise 的函数被称为 executor。当 new Promise 被创建,executor 会自动运行。
它的参数 resolve 和 reject 是由 JavaScript 自身提供的回调。我们的代码仅在 executor 的内部。
当 executor 获得了结果,无论是早还是晚都没关系,它应该调用以下回调之一:
-
resolve(value) — 如果任务成功完成并带有结果 value。
-
reject(error) — 如果出现了 error,error 即为 error 对象。
所以总结一下就是:executor 会自动运行并尝试执行一项工作。尝试结束后,如果成功则调用 resolve,如果出现 error 则调用 reject。
由 new Promise 构造器返回的 promise 对象具有以下内部属性:
Promise有三种状态state
最初是 "pending",然后在 resolve 被调用时变为 "fulfilled",或者在 reject 被调用时变为 "rejected"。
三种事件状态由"pending"变为 "fulfilled"或"rejected"后不可倒流回"pending"状态
比如:学校要举行期末考试,等待考试状态是"pending",成功开展考试变是 "fulfilled",由于疫情原因小伙伴们提前撤退没有参与考试是"rejected",都不再回到等待考试状态。
每一种状态会对应result结果
result 最初是 undefined,然后在 resolve(value) 被调用时变为 value,或者在 reject(error) 被调用时变为 error。
等待时undefined,成功开展考试可以得到各个学生的试卷内容resolve(value),或者没能举办考试得到开展失败reject(error)的记录
所以,executor 最终将 promise 移至以下状态之一:
Promise.all()与Promise.race()
Promise.all()
微信发朋友圈时,想上传9张图片到云存储,类似这种等待所有事件完成再执行后续操作一般使用Promise.all()
以下是对成功 fulfulled 的 promise 使用.then做出的反应:
setTimeout(code/function, milliseconds, param1, param2, ...)用于在指定的毫秒数后调用函数或计算表达式。
Promise.all()会等待数组里面所有promise的executor 运行完毕后再以.then()处理
例如,以下是对失败 rejected 的 promise 使用.catch做出的反应:
Promise.all()会等待数组里面所有promise的executor 运行一旦执行reolve()回调则认为事物失败,再以.catch()处理,且脚b本程序可继续执行。
Promise.race()
Promise.race()[p1,p2])只要有一个请求完成就会触发后面.then(),
常用于判断请求是否超时
比如p1事件,p2是个定时器,如果先执行p2,就可以知道p1超时了,该做些其他操作。
Async/Await
在云函数里,由于 Node 版本最低是 8.9,因此是天然支持 async/await 语法的。而在小程序旧版本则不然。
两种方式解决:
①直接改变基础库环境,到新版本
②配置相关工具,需要下载并引入额外的文件。可把这个 regenerator/runtime.js 文件引用到有使用 async/await 的文件当中。手动import regeneratorRuntime
https://gitee.com/longyorke/miniprogram_async_await/tree/master/
Async
在函数前面的 “async” 这个单词表达了一个简单的事情:即这个函数总是返回一个 promise。其他值将自动被包装在一个 resolved 的 promise 中。
下面这个函数返回一个结果为1的 resolved promise,
async function f() {
return 1;
}
f().then(alert); // 1
等效于
async function f() {
return Promise.resolve(1);
}
f().then(alert); // 1
Await
关键字 await 让 JavaScript 引擎等待直到 promise 完成(settle)并返回结果。
只在 async 函数内工作
(async () => {
await this.example();
})()
这里的例子就是一个 1 秒后 resolve 的 promise,alert的内容需要等待完整的信息传入:
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000)
});
let result = await promise; // 等待,直到 promise resolve
alert(result); // "done!"
}
f();
await 使得不会进行后面依赖函数的执行,直到 promise 状态变为 settled,然后以 promise 的结果继续执行。
在page.js中我们一般把函数定义放在钩子回调函数同层级下,在生命周期函数里面执行
onLoad: function (options) {
console.log(this.example())
},
async example(){
console.log("example")
return 1
},
相比于 promise.then,它只是获取 promise 的结果的一个更优雅的语法,同时也更易于读写。
async/await 可以和 Promise.all 一起使用
// 等待结果数组
let results = await Promise.all([
require(url1),
require(url2),
...
]);
如果出现 error,也会正常传递,从失败了的 promise 传到Promise.all,然后变成我们能通过使用try..catch在调用周围捕获到的异常(exception)。
使用try..catch,如果有 error 发生,执行控制权马上就会被移交至catch块。
async function f() {
try {
const rp = require("request-promise")
let response = await rp('/no-user-here');
let user = await response .json();
} catch(err) {
// 捕获到 rp和 response.json 中的错误
alert(err);
}
}
f();
如果我们没有try..catch,发生错误后,那么由异步函数f()的调用生成的 promise 状态为 rejected。我们可以在函数调用后面添加.catch来处理这个 error:
async function f() {
const rp = require("request-promise")
let response = await rp('/no-user-here');
}
// f() 变成了一个 rejected 的 promise
f().catch(alert); // TypeError: failed to fetch // (*)
async/await是基于 promise 的,因此我们可以同时使用promise.then/catch与async/await
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)