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);
对于addRoomData
和addReservationData
函数,您可能需要将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 });