关于 promise链式调用与中止

关于 promise链式调用与中止

用 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 方法链来调用。相比用回调函数而言,代码结构更加清晰,也更易读易懂耦合度更低更易扩展了。

你可能感兴趣的:(js)