2016-02-25 42 views
0

從2016年開始,Node自從v4以來已經擁有了近乎完整的ES6支持,而Promises自0.12開始就已經有了。現在是時候留下灰塵IMO回調。通過使用`co`封裝來回調異步的正確方法?

我正在研究基於commander.js的CLI util,它利用了很多異步操作 - http請求和用戶輸入。我想包裝指令器action s異步函數,以便它們可以被視爲承諾,並且還支持生成器(對於我用於用戶輸入的co-prompt庫有用)。

我已經試過包裝與co的CB在兩個方面:

1) program.command('myCmd') .action(program => co(function* (program) {...}) .catch(err => console.log(err.stack)));

2)program.command('myCmd').action(co.wrap(function* (program) { .. }));

1的問題)是,program參數不通過

T他與2)的問題是,錯誤被吞噬...

我真的想得到這個工作,因爲它在我的用例中產生更好的代碼 - 涉及大量的http請求,也等待用戶輸入使用co-prompt圖書館..

總而言之,這可能是一個更好的選擇,或者以某種方式包裝program.Command.prototype.action

謝謝!

回答

0

我已經使用定製版本的類似co獲得db.exec函數,它使用yield來執行數據庫請求。你可以將參數傳遞給一個生成器函數(我傳入一個連接對象 - 請參閱我在其中執行的註釋)。

下面是db.exec功能非常類似於co確實

exec(generator) { 
    var self = this; 
    var it; 
    debug('In db.exec iterator'); 
    return new Promise((accept,reject) => { 
    debug('In db.exec Promise'); 
    var myConnection; 
    var onResult = lastPromiseResult => { 
     debug('In db.exec onResult'); 
     var obj = it.next(lastPromiseResult); 
     if (!obj.done) { 
     debug('db.exec Iterator NOT done yet'); 
     obj.value.then(onResult,reject); 
     } else { 
     if (myConnection) { 
      myConnection.release(); 
      debug('db.exec released connection'); 
     } 
     accept(obj.value); 
     debug('db.exec Promise Resolved with value %d',obj.value); 
     } 
    }; 
    self._connection().then(connection => { 
     debug('db.exec got a connection'); 
     myConnection = connection; 
     it = generator(connection); //This passes it into the generator 
     onResult(); //starts the generator 
    }).catch(error => { 
     logger('database', 'Exec Function Error: ' + error.message); 
     reject(error); 
    }); 
    }); 
} 

連接對象也是由數據庫連接對象封裝,並提供用於處理從結果的行發電機功能的能力數據庫,但我不會在這裏發佈(雖然下面的例子是使用它來處理行)。

這裏是使用exec函數來運行的SQL

db.exec(function*(connection) { 
     if (params.name === ADMIN_USER) { 
     debug('Admin Logon'); 
     user.name = ADMIN_DISPLAY; 
     user.keys = 'A'; 
     user.uid = 0; 
     let sql = 'SELECT passwordsalt FROM Admin WHERE AdminID = 0'; 
     connection.request(sql); 
     yield connection.execSql(function*() { 
      let row = yield; 
      if (row) { 
      user.nopass = (row[0].value === null); 
      } else { 
      user.nopass = false; 
      } 
      debug('Admin Password bypass ' + user.nopass.toString()); 
     }); 
     } else { 
     debug('Normal User Logon'); 
     let sql = `SELECT u.UserID,PasswordSalt,DisplayName,AccessKey,l.LogID FROM Users u 
      LEFT JOIN UserLog l ON u.userID = l.userID AND DATEDIFF(D,l.LogDate,GETDATE()) = 0 
      WHERE u.UserName = @username`; 
     let request = connection.request(sql); 
     request.addParameter('username',db.TYPES.NVarChar,params.name); 
     let count = yield connection.execSql(function*() { 
      let row = yield; 
      if (row) { 
      user.uid = row[0].value; 
      user.name = row[2].value; 
      user.keys = (row[3].value === null) ? '' : row[3].value; 
      user.nopass = (row[1].value === null) ; 
      user.lid = (row[4].value === null) ? 0 : row[4].value; 
      debug('Found User with uid = %d and lid = %d, keys = %s', 
       user.uid, user.lid, user.keys); 
      } 
     }); 
     if (count === 0) { 
      debug('Not Found User'); 
      // couldn't find name in database 
      reply(false,false); 
      return; 
     } 
     } 
     if (!user.nopass) { 
     debug('Need a Password'); 
     //user has a password so we must check it 
     passGood = false; //assume false as we go into this 
     let request = connection.request('CheckPassword'); 
     request.addParameter('UserID',db.TYPES.Int,user.uid); 
     request.addParameter('password',db.TYPES.VarChar,params.password); 
     yield connection.callProcedure(function*() { 
      let row = yield; 
      if (row) { 
      //got a valid row means we have a valid password 
      passGood = true; 

      } 
     }); 
     } else { 
     passGood = true; 
     } 
     if (!passGood) { 
     debug('Not a Good Pasword'); 
     reply(false,true); 
     } else { 
     if (user.uid !== 0 && user.lid === 0) { 
      let sql = `INSERT INTO UserLog(UserID,LogDate,TimeOn,UserName) OUTPUT INSERTED.logID 
      VALUES(@uid,GETDATE(),GETDATE(),@username)`; 
      let request = connection.request(sql); 
      request.addParameter('uid',db.TYPES.Int,user.uid); 
      request.addParameter('username',db.TYPES.NVarChar,user.name); 
      yield connection.execSql(function*() { 
      let row = yield; 
      if (row) { 
       user.lid = row[0].value; 
       debug('Users Log Entry = %d',user.lid); 
      } 
      }); 
     } 
     reply(true,user); 
     } 
    }) 
    .catch((err) => { 
     logger('database','Error on logon: ' + err.message); 
     reply(false,false); 
    }); 
    }); 
的序列的一個例子