NodeJS我的SQL查询与链承诺

我有3个function,我想调用这个function一步一步,例如,当我将调用第一function和得到的结果,我不得不调用第二个function,并传递从第一次调用返回的参数。 在完成第二次调用之后,我必须调用第三个函数并传递从第二个函数返回的参数。

#1:

getCategory = function (branch_id) { var deferred = q.defer(); var categoryData; var query = 'SELECT id,name,price,currency FROM category where branch_id=?'; pool.getConnection(function (err, connection) { connection.query(query, [branch_id], function (error, row, fields) { if (error) { deferred.reject(error); } else { connection.release(); deferred.resolve(row); } }); }); return deferred.promise; } 

#2:

 getRoom = function (branch_id, categoryID) { var deferred = q.defer(); var roomData; var roomSql = 'SELECT id,room_no,name,price,currency FROM room where branch_id=? and category_id=?'; pool.getConnection(function (err, connection) { connection.query(roomSql, [branch_id, categoryID], function (error, row, fields) { if (err) { deferred.reject(err); } else { connection.release(); deferred.resolve(row); } }); }); return deferred.promise; } 

#3:

 getReservationL = function (room_id, start_date, end_date) { var deferred = q.defer(); var reservationData; var reservationSql = 'SELECT d.id,d.create_date,d.update_date,d.room_id,d.status_id,d.start_date,d.end_date, ' + ' s.name as status_name,a.id as reservation_id,a.person_no as person_no, p.first_name,p.last_name,p.email ' + ' FROM reservation_detail d ' + ' inner join reservation_status s on d.status_id=s.id ' + ' inner join reservation a on d.reservation_id=a.id ' + ' inner join person p on a.person_no=p.personal_no ' + ' where d.room_id=? and d.start_date >? and d.start_date<?'; pool.getConnection(function (err, connection) { connection.query(reservationSql, [room_id, start_date, end_date], function (error, row, fields) { if (err) { deferred.reject(err); } else { connection.release(); deferred.resolve(row); } }); }); return deferred.promise; } 

我需要这样的东西:

 data = getCategory() for(i=0;i<data.length;i++){ data[i].room = getRoom(data[i].id); for(j=0;j<data[i].room[j].length;j++){ data[i].room[j].reservation = getReservationL(data[i].room[j].id); } } 

如何使用promise或callback在NodeJS中实现这个伪代码。 我宁愿使用诺言。

更新#1我有第二次迭代后的数据

 [ { "id": 64, "name": "VIP", "price": 116.5, "currency": "USD", "room": [ { "id": 44, "room_no": "101", "name": "A", "price": 100, "currency": "EUR" }, { "id": 274, "room_no": "505", "name": "a", "price": 1, "c\r\nurrency": "GEL" } ] }, { "id": 74, "name": "SUPER VIP", "price": 110, "currency": "EUR", "room": [ { "id": 54, "room_no": "102", "name": "A", "price": 100, "currency": "GEL" }, { "id": 284, "room_no": "606", "name": "a", "price": 1, "currency": "GEL" } ] }, { "id": 84, "name": "DOUBLE", "price": 110, "currency": "GEL", "room": [ { "id": 204, "room_no": "103", "name": "b", "price": 120, "currency": "GEL" } ] } ] 

我魔杖遍历每个类别的每个房间。

  getCategory(branch_id).then(firstRecords => { let promises = firstRecords.map(function (record) { return getRoom(branch_id, record.id) .then(roomData => { var res = Object.assign({}, record, { room: roomData }); return res; }) }); return Promise.all(promises); //HERE i have data that is placed above. }).then(secondRecords => { let promises = secondRecords.map(function (category) { return category.room; }).map(function (rooms) { console.log('SECOND', rooms); return rooms; }).map(function (reservation) { console.log('THERD', reservation); return reservation; }) return Promise.all(promises); }).then(reservation => { console.log("Reservation", reservation); }) 

更新#2最终解决scheme在这里

 getCategory(branch_id) .then( categories => { let roomPromises = categories.map( category => { return getRoom(branch_id, category.id) .then( rooms => Object.assign({}, category, { rooms }) ) }); return Promise.all(roomPromises) }) .then( category_rooms => { let finalPromise = category_rooms.map( category => { let reservationPromises = category.rooms.map( room => { return getReservationL(room.id, start_date, end_date) .then( reservations => Object.assign({}, room, { reservations }) ) }) return Promise.all(reservationPromises) .then( room_reservations => { return Object.assign({}, category, { rooms: room_reservations }) }); }) // const flattenPromise = finalPromise.reduce( (a, b) => a.concat(b), []); // return Promise.all(flattenPromise); return Promise.all(finalPromise) }) .then( data => console.log('final: ', data) ) 

您可以使用.then来parsing承诺.then然后可以链接,以同步方式解决多个承诺。

也许这会解决你的使用案例。

 getCategory() .then( firstRecords => { console.log('firstRecords: ', firstRecords); let promises = firstRecords.map( record => getRoom(record) ); return Promise.all(promises); }) .then( secondRecords => { console.log('secondRecords: ', secondRecords); let promises = secondRecords.map( record => getReservationL(record) ); return Promise.all(promises); }) .then( thirdRecords => { console.log('thirdRecords: ', thirdRecords); }) 

参考: 承诺然后链接

then方法返回一个允许方法链接的Promise。

如果该函数作为处理程序传递,然后返回一个Promise,则相应的Promise将暴露于随后的方法链中

参考: 全部承诺

Promise.all()方法返回一个单独的Promise,它parsing了当iterable参数中的所有promise都解决了的时候,或者iterable参数中没有promise的时候。 它拒绝了拒绝的第一个承诺的原因。

 Promise.all([ { key: 1 }, Promise.resolve(3), 1, true ]) .then( results => { results[0]; // { key: 1 } results[1]; // 3 results[2]; // 1 results[3]; // true }) 

更新#1

Promise.all只接受一个promise的数组而不是在key上承诺的对象。

 # wrong Promise.all([ { key: Promise.resolve(1) }, { key: Promise.resolve(2) }, { key: Promise.resolve(3) }, ]) # right Promise.all([ Promise.resolve(1), Promise.resolve(2), Promise.resolve(3) ]) 

你可以做这样的事情来实现你在评论中提到的内容。

 getCategory(branch_id) .then( firstRecords => { console.log('firstRecords: ', firstRecords); let promises = firstRecords.map( record => { return getRoom(branch_id, record.id) .then( roomData => Object.assign({}, record, { room : roomData }) ) }); return Promise.all(promises) }) 

如果你想追加第一个和第二个承诺的数据,那么解决那里的承诺只能访问一个地方的数据。

更新#2

正如你在评论中提到的,这段代码可能会帮助你。

 getCategory(branch_id) .then( categories => { let roomPromises = categories.map( category => { return getRoom(branch_id, category.id) .then( rooms => Object.assign({}, category, { rooms }) ) }); return Promise.all(roomPromises) }) .then( category_rooms => { let finalPromise = category_rooms.map( category => { let reservationPromises = category.rooms.map( room => { return getReservationL(room.id, start_date, end_date) .then( reservations => Object.assign({}, room, { reservations }) ) }) return Promise.all(reservationPromises) .then( room_reservations => { return Object.assign({}, category, { rooms: room_reservations }) }); }) return Promise.all(finalPromise) }) .then( data => console.log(data) ) 

由于您的逻辑包含大量用于数据select和转换的loop语句,因此您需要将其重构为如下所示的内容:

 getCategory(brandId) .then(addRoomData) .then(addReservationData) .then(handleFinalData) .catch(handleError); 

对于addRoomDataaddReservationData函数,您可能需要将Promise.all()与.forEach()结合使用

如果您想以更易读的方式编写代码,请考虑使用async / await

我认为更优化的方法是使用asynchronous模块的async.waterfall函数。 https://caolan.github.io/async

 async.waterfall([ function(callback) { getSomething(options, function (err, result) { if (err) { callback(new Error("failed getting something:" + err.message)); // we should return here } // since we did not return, this callback still will be called and // `processData` will be called twice callback(null, result); }); }, function(data, callback){ //do something } ], function(err,results){ //get final results });