【小程序】007 Promise与Async/Await

举报
LongYorke 发表于 2021/02/01 19:03:03 2021/02/01
【摘要】 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 会自动运行。
它的参数 resolvereject 是由 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

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。