JS Promise 扫盲兼快速上手「初识 Promise 3 态」

424 阅读3分钟

「这是我参与11月更文挑战的第 1 天,活动详情查看:2021最后一次更文挑战

为什么需要 Promise

在某些场景下,我们的下一步操作,需要依赖上一步的结果,但这个结果又是异步获取的(典型的场景就是去请求 api 的数据)。

比如,我们复刻上一步的场景,再重复一定的次数,伪代码写起来就可以得到类似如下的经典代码:

image.png

如果回调中没有什么麻烦的操作,我们可以得到让人血压升高的逐行收尾的 })

若再参合上复杂的处理逻辑,是重构还是捋着改,反正都是痛苦面具😣

外国的同行称之为:Callback Hell--- 回调函数地狱。歪果仁甚至以此为域名建立了一个网站:callbackhell.com 里面详细解释了callback hell并给出解决方案和建议。

Promise 是什么

image.png

翻译过来就是期约,指在当前单线程环境下,代码块没法立即返回数据或者执行某些处理,需要等待某个条件达到后,才会执行前面说的处理

一个更加直白的描述,Promise 的出现就是用于解决 js 中的多线程需求

Promise 3 态

待定(pendding)

Promise 通过 new 初始化后,默认处于待定的状态。

如果程序设计不合理,Promise 会一直处于 待定 状态,这个是有可能的。

当我们预计程序有可能会有出现上述的情况时,需要添加超时处理,伪代码如下:

new Promise((resolve, reject) => {
    doThings(); // use long time
    setTimeout(() => reject(), 10 * 1000); // 10s timeout
})

兑现(fulfilled,更习惯称为 resolve)

当我们认为 Promise 已经解决时,可以修改状态为 兑现

如果我们需要对异步获取的值做回调处理时,常规做法就是嵌入回调函数

而现在更建议用 Promise.then() 来平级处理回调,伪代码如下:

new Promise((resolve, reject) => {
    let data = doThings(); // 异步获取的结果
    resolve(data);         // 获取的值,交给 resolve 进行包装
}).then(data => {  // then 会自动解析得到 data 对象
    // callback(data);
});

失败(reject)

如果在 Promise 处理的过程中,需要针对一些异常做处理

这里的异常,分为两种:

  1. 是期约内部的程序运行报错
  2. 期约中的程序运行结果不符合我们的期望,也需要报错处理

举一个🌰,请求一个接口返回 404,请求是成功的,但请求的结果不是我们需要的 200,我们认为这也是异常返回,可以修改状态为 失败,强烈建议传递失败的原因,供后续的 .catch() 使用,针对这个也上一份伪代码

new Promise((resolve,reject)=>{
  $.get(url, function(data) {
    if (data.status == 404) {
      reject(data.msg);
    } else {
      resolve(data)
    }
  })
}).then(data=>callback(data))  // then 会自动解析得到 data 对象
.catch(e=>console.log(e));     // catch 会解析 reject 中传递的异常信息

注:Promise 一旦从待定状态变更后,就不在支持状态变更,比如:

new Promise((resolve,reject)=>{
  resolve();  // 第一次变更状态,成功
  reject();   // 第二次变更状态,失败
})