「这是我参与11月更文挑战的第 1 天,活动详情查看:2021最后一次更文挑战」
为什么需要 Promise
在某些场景下,我们的下一步操作,需要依赖上一步的结果,但这个结果又是异步获取的(典型的场景就是去请求 api 的数据)。
比如,我们复刻上一步的场景,再重复一定的次数,伪代码写起来就可以得到类似如下的经典代码:
如果回调中没有什么麻烦的操作,我们可以得到让人血压升高的逐行收尾的 })
若再参合上复杂的处理逻辑,是重构还是捋着改,反正都是痛苦面具😣
外国的同行称之为:Callback Hell--- 回调函数地狱。歪果仁甚至以此为域名建立了一个网站:callbackhell.com 里面详细解释了callback hell并给出解决方案和建议。
Promise 是什么
翻译过来就是期约,指在当前单线程环境下,代码块没法立即返回数据或者执行某些处理,需要等待某个条件达到后,才会执行前面说的处理
一个更加直白的描述,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 处理的过程中,需要针对一些异常做处理
这里的异常,分为两种:
- 是期约内部的程序运行报错
- 期约中的程序运行结果不符合我们的期望,也需要报错处理
举一个🌰,请求一个接口返回 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(); // 第二次变更状态,失败
})