用 new Promise 实例化的 promise 对象有以下三个状态:
- “has-resolution” - Fulfilled。resolve(成功)时,此时会调用 onFulfilled
- “has-rejection” - Rejected。reject(失败)时,此时会调用 onRejected
- “unresolved” - Pending。既不是resolve也不是reject的状态,也就是promise对象刚被创建后的初始化状态等
promise是如何进行链式调用的:
- promise 的 then 方法里面可以继续返回一个新的 promise 对象
- 下一个 then 方法的参数是上一个 promise 对象的 resolve 参数
- catch 方法的参数是其之前某个 promise 对象的 rejecte 参数
- 一旦某个 then 方法里面的 promise 状态改变为了 rejected,则promise 方法连会跳过后面的 then 直接执行 catch
- catch 方法里面依旧可以返回一个新的 promise 对象
如何中止 promise 方法链:
- 我们可以知道 promise 的状态改变为 rejected 后,promise 就会跳过后面的 then 方法。也就是,某个 then 里面发生异常后,就会跳过 then 方法,直接执行 catch),所以,当在构造的 promise 方法链中,如果在某个 then 后面,不需要再执行 then 方法了,就可以把它当作一个异常来处理,返回一个异常信息给 catch,其参数可自定义,比如该异常的参数信息为 { notRealPromiseException: true},然后在 catch 里面判断一下 notRealPromiseException 是否为 true,如果为 true,就说明不是程序出现异常,而是在正常逻辑里面中止 then 方法的执行
可行方案总结就是无非这两种:
- return (new Promise((resolve, reject)=>{}));//返回pending状态
- return (new Promise((resolve, reject)=>{reject()}));//返回reject状态 会被最后catch捕获。
代码大概长这样:
start()
.then(data => {
// promise start
console.log('result of start: ', data);
return Promise.resolve(1); // p1
)
.then(data => {
// promise p1
console.log('result of p1: ', data);
return Promise.reject({
notRealPromiseException: true,
}); // p2
})
.then(data => {
// promise p2
console.log('result of p2: ', data);
return Promise.resolve(3); // p3
})
.catch(ex => {
console.log('ex: ', ex);
if (ex.notRealPromiseException) {
// 一切正常,只是通过 catch 方法来中止 promise chain
// 也就是中止 promise p2 的执行
return true;
}
// 真正发生异常
return false;
})
注意:这样的做法可能不符合 catch 的语义。不过从某种意义上来说,promise 方法链没有继续执行,也可以算是一种“异常”
讲了那么多道理,现在就改来使用 promise 重构之前用回调函数写的异步逻辑了。
// 据 name 查询用户信息
const findUserByName = (name, pwd) => {
return new Promise((resolve, reject) => {
// 数据库查询操作
if (dbError) {
// 数据库查询出错,将 promise 设置为 rejected
reject({
code: 1000,
message: '查询用户信息,数据库操作数出现异常',
});
}
// 将查询结果赋给 userinfo 变量
if (userinfo.length === 0) {
// 数据库中不存在该用户
resolve();
}
// 数据库存在该用户,判断密码是否正确
if (pwd === userinfo[0].pwd) {
// 密码正确,中止 promise 执行
reject({
notRealPromiseException: true,
data: {
code: 0,
message: '密码正确,登录成功',
}
});
}
// 密码不正确,登录失败,将 Promise 设置为 Rejected 状态
reject({
code: 1001,
message: '密码不正确,登录失败',
});
});
};
// 模拟登录教务系统
const loginEducationSystem = (name, pwd) => {
// 登录逻辑...
// 登录成功
resolve();
// 登录失败
reject({
code: 1002,
message: '模拟登录教务系统失败',
});
};
// 将用户名密码存入数据库
const saveUserToDB(name, pwd) => {
// 数据库存储操作
if (dbError) {
// 数据库存储出错,将 promise 设置为 rejected
reject({
code: 1004,
message: '数据库存储出错,将出现异常',
});
}
// 数据库存储操作成功
resolve();
};
findUserByName(name)
.then(() => {
return loginEducationSystem(name, pwd);
})
.then(() => {
return saveUserToDB(name, pwd);
})
.catch(e => {
// 判断异常出现原因
if (e.notRealPromiseException) {
// 正常中止 promise 而故意设置的异常
return res.json(e.data);
}
// 出现错误或异常
return res.json(e);
});
在上面的代码中,实例化了三个 promise 对象,分别实现业务需求中的三个功能。然后通过 promise 方法链来调用。相比用回调函数而言,代码结构更加清晰,也更易读易懂耦合度更低更易扩展了。