如何 处理Promise 过程中的错误
发布于 9 年前 作者 xinshangshangxin 17977 次浏览 最后一次编辑是 8 年前 来自 问答

如何解决在各种检查的过程中, 记录返回的错误code,并且返回给前端

以前是直接 return

function(req, res) {
  var user = req.body;

  if (!user.username) {
    return res.json({
      msg: 'no username',
      code: 1
    });
  }
  if (!user.password) {
    return res.json({
      msg: 'no password',
      code: 2
    });
  }

  if (!user.code) {
    return res.json({
      msg: 'no code',
      code: 3
    });
  }

  return checkCode(user)
    .then(function(data) {
      return checkPassword(user);
    })
    .then(function() {
      return res.json({
        msg: 'login success'
      });
    })
    .catch(function(err) {
      console.warn(err);
      return res.json({
        msg: 'login fail',
        code: 4
      });
    });
}

但是如果用 Promise 包装过后, return 只是到下一个 Promise, 下面的写法 在bb3.0+ 中会 warning Promise.reject需要一个error 有没有一种比较好的解决方式呢?

function(req, res) {
  var user = req.body;

  return Promise
    .resolve(function() {
      if (!user.username) {
        return Promise.reject({
          msg: 'no username',
          code: 1
        });
      }

      if (!user.password) {
        return Promise.reject({
          msg: 'no password',
          code: 2
        });
      }

      if (!user.code) {
        return Promise.reject({
          msg: 'no code',
          code: 3
        });
      }

      return checkCode(user)
        .then(function(data) {
          return checkPassword(user);
        });
    })
    .then(function() {
      return res.json({
        msg: 'login success'
      });
    })
    .catch(function(err) {
      /**
  	  err 可能是 no password 或者 no code 等各种错误
  		**/
      return res.json(err);
    });
}

18 回复

先去好好看看promise吧

来自酷炫的 CNodeMD

按你这种写法,也没有问题,只是会报warning。如果想不报warning的话,Promise.reject(new Error(‘这里面定义你的错误’))

@imhered new Error 的话, 不能同时存储 msg 和 code了, 有没有更好的办法?

@iyuq 说了等于没说, 连哪里问题都不说明?

@xinshangshangxin 没用更好的办法了,就让他warning吧,我现在全都是reject的或者throw

let err = new Error('你的错误消息');
err.status = 400;
return Promise.reject(err);

这样就既有code又有message了。也可以自己写一个创建err的函数:function createError(status, message)

可以继承 Promise.OperationalError ,把 code 加进去,然后 Promise.reject(new MyError(CODE, MSG)) 。不要通过另一个 function 创建,这样可以快速定位 reject 发生的位置,然后在 error 里面统一捕获再返回 res.json

来自酷炫的 CNodeMD

@klesh 是这样吗? 但是 快速定位 reject 发生的位置 没有理解

var util = require('util');
var Promise = require('bluebird');

var myError = function(code, message) {
  this.code = code;
  this.message = message;
};

util.inherits(myError, Promise.OperationalError);

Promise
  .resolve()
  .then(function() {
    return Promise.reject(new myError(400, '123'));
  })
  .catch(function(e) {
    // { [Error: 123] code: 400, message: '123' }
    console.log(e);
  });

@iyuq 谢谢, 但是这样写是不是有些绕圈子? 在实际开发中是怎么处理的呢?

用 async await 吧,promise 解决不了嵌套问题。

为什么要这么写代码 硬生生把不是异步的部分也扯进Promise里去 我习惯这么干:

function checkCode(code) {
    return new Promise(funtion(resolve, reject) {
        // todo
        if(true) resolve()
        else reject(err)
    })
}

function checkPassword(pass) {
    return new Promise(funtion(resolve, reject) {
        // todo
        if(true) resolve()
        else reject(err)
    })
}

function(req, res) {
    // 上面的不变

    checkCode(user)
        .then(checkPassword)
        .catch(err) {
            res.json({code: 4, msg: err})
        }
}

在请求的handler里边返回Promise是没有啥意义的。

@chemdemo 首先谢谢回答!

但是问题的重点不再这块 重点是: 对于 “no username” 的code为 1 对于 "no password"的code为2
对于 "验证码错误"的code为3
所以我希望得到一个 promise reject中 同时带有 errCode 和 errMsg的

你的写法 code只有一个了

checkCode(user)
  .then(checkPassword)
  .catch(err) {
    res.json({code: 4, msg: err})
  }

问题是: 如何区分多种错误, 返回是带上errCode 和 errMsg

@285858315 还没有标准化, 不准备用babel

你现在的情况比较简单,但随着应用越来越复杂。可能会出现a使用了b,b使用了c,c使用了d,d reject了。a却忘了处理error, 这时bluebird能打印出原始的stack信息以及reject发生的位置。那一眼就能明白问题出在哪里了。

来自酷炫的 CNodeMD

@klesh 这个方法好像很好呢,这样reject的时候就不会warning了

@klesh 大概懂了, 谢谢!!!

var util = require('util');
var Promise = require('bluebird');

var MyError = function(code, message) {
  this.code = code;
  Promise.OperationalError.call(this, message);
};
util.inherits(MyError, Promise.OperationalError);

function myError2(code, message) {
  var e = new Error(message);                        //默认报错在这里
  e.code = code;
  return e;
}


function MyError3(code, message, constr) {
  Error.captureStackTrace(this, constr || this);   // 默认报错在这里
  this.code = code;
  this.message = message || 'Error'
}
util.inherits(MyError3, Error);

Promise
  .resolve()
  .then(function() {
    return Promise.reject(new MyError(400, '123'));  //默认报错在这里
  });

Promise
  .resolve()
  .then(function() {
    return Promise.reject(myError2(400, 'test'));   //默认报错在 myError2 内部
  });

Promise
  .resolve()
  .then(function() {
    return Promise.reject(new MyError3(400, 'test'));//默认报错在 MyError3 内部
  });
回到顶部