对多个方法使用相同的catch块

时间:2016-01-14 16:59:50

标签: node.js error-handling promise catch-block

假设:

  • NodeJS v0.10.25
  • 启用所有和声功能
  • "use strict"

以下代码:

   db.connect({
      host: DB_HOST,
      port: DB_PORT
    }).then(function(dbConn) {
      console.log('DBASE connected to ' + DB_HOST + ':' + DB_PORT);
      db.dbList().run(dbConn).then(function(result) {
        if (result.indexOf(SCRIPT_NAME) == -1) throw new Error('unable to locate database ' + SCRIPT_NAME);
        dbConn.use(SCRIPT_NAME);
        console.log('DBASE bound to ' + SCRIPT_NAME + ' on ' + DB_HOST + ':' + DB_PORT);
        db.tableList().run(dbConn)
          .then(function(result) {
            if (!result) throw new Error(SCRIPT_NAME + ' unable to enumerate tables');
            if (!result.length) throw new Error(SCRIPT_NAME + ' has no tables');
            console.log('DBASE ' + DB_HOST + ':' + DB_PORT + '/' + SCRIPT_NAME + ' has ' + result.length + ' table' + ((result.length > 1) ? 's' : ''));
          }).catch(function(err) {
            console.error('DBASE ' + err);
          });
      }).catch(function(err) {
        console.error('DBASE ' + err);
      });
    }).catch(function(err) {
      console.error('DBASE ' + err);
    });

注意多个相同的catch块:

.catch(function(err) {
          console.error('DBASE ' + err);
        });

是否有推荐/接受/事实上的方法在多个控制结构级别重用该异常处理程序?

2 个答案:

答案 0 :(得分:2)

错误将会消失,直到它们被捕获,因此您不需要多次捕获,并且您可以通过链接您的承诺而不是嵌套它们来使您的代码更具可读性:

db.connect({
  host: DB_HOST,
  port: DB_PORT
}).then(function(dbConn) {
  console.log('DBASE connected to ' + DB_HOST + ':' + DB_PORT);
  // it's important to return if you have a promise so the chain doesn't break
  return db.dbList().run(dbConn);
}).then(function(result) {
  if (result.indexOf(SCRIPT_NAME) == -1) throw new Error('unable to locate database ' + SCRIPT_NAME);
  dbConn.use(SCRIPT_NAME);
  console.log('DBASE bound to ' + SCRIPT_NAME + ' on ' + DB_HOST + ':' + DB_PORT);
  return db.tableList().run(dbConn);
}).then(function(result) {
  if (!result) throw new Error(SCRIPT_NAME + ' unable to enumerate tables');
  if (!result.length) throw new Error(SCRIPT_NAME + ' has no tables');
  console.log('DBASE ' + DB_HOST + ':' + DB_PORT + '/' + SCRIPT_NAME + ' has ' + result.length + ' table' + ((result.length > 1) ? 's' : ''));
}).catch(function(err) {
  console.error('DBASE ' + err);
});

答案 1 :(得分:0)

ShanShan的回答是正确的,但既然你说你在现代节点上使用ES2015就可以使用更现代的语法:

db.connect({
  host: DB_HOST,
  port: DB_PORT
}).then(dbConn => {
  console.log(`DBASE connected to ${DB_HOST} : ${DB_PORT}`);
  return db.dbList().run(dbConn);
}).then(result =>{
  if (!result.includes(SCRIPT_NAME)) 
    throw new Error(`unable to locate database ${SCRIPT_NAME}`);
  dbConn.use(SCRIPT_NAME);
  console.log(`DBASE bound to ${SCRIPT_NAME} on ${DB_HOST} : ${DB_PORT}`);
  return db.tableList().run(dbConn);
}).then(result => 
  if (!result) throw new Error(`${SCRIPT_NAME} unable to enumerate tables`);
  if (!result.length)  throw new Error(`${SCRIPT_NAME has no tables`);
  console.log(`DBASE ${DB_HOST} : ${DB_PORT}/${SCRIPT_NAME} has ` + `
              `${result.length}  table ${((result.length > 1) ? 's' : '')}`);

process.on('unhandledRejection', (p) => console.error('DBASE', p)); // global handler

更进一步,如果我们使用发电机泵,代码可以写成:

function co(gen) { // your friendly neighborhood generator pump
   var it = gen(); 
   return Promise.resolve().then(function next(v){ 
      let r = it.next(v);
      if(r.done) return r.value;
      return Promise.resolve(r.value).then(next, e => it.throw(e));
   });
}

co(function*() { // console logs ommitted for brevity
  const db = yield db.connect({host: DB_HOST, port: DB_PORT }); 
  const list = yield db.dbList().run(dbConn);
  if(!result.includes(SCRIPT_NAME))
    throw new Error(`unable to locate database ${SCRIPT_NAME}`);
  db.use(SCRIPT_NAME);
  const tables = db.tableList().run(db);
  if(!tables) throw new Error(`${SCRIPT_NAME} unable to enumerate tables`);
  if(!tables.length) throw new Error(`${SCRIPT_NAME} has no tables`);
  return tables; // this still returns a promise, you can chain off it
});

这就是它,完全平坦,您可以在那里使用同步try / catch,如果您愿意,它可以使用.catch生成的承诺。

您可以使用像bluebird这样的库来代替协程而不是上面的co函数,它可以为您提供更好的堆栈跟踪和更快的承诺。