我有3个功能,我想逐步调用此函数,例如当我将调用firs函数并获得结果时,我必须调用第二个函数并传递从第一个调用返回的参数。在我完成第二次调用后,我必须调用第三个函数并传递从第二个函数返回的参数。
#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 最终解决方案就在这里
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) )
答案 0 :(得分:2)
您可以使用.then
解决承诺,并可以链接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.all()方法返回一个Promise,它在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
})
Promise.all
只接受一个promise数组,而不是对象上的promises对象。
# 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)
})
如果你想追加第一个和第二个诺言的数据,那么解决那里的承诺只能在一个地方访问两者的数据。
正如您在评论中提到的,此代码可能会对您有所帮助。
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) )
答案 1 :(得分:0)
由于您的逻辑包含大量用于数据选择和转换的loop
语句,因此您需要将其重构为:
getCategory(brandId)
.then(addRoomData)
.then(addReservationData)
.then(handleFinalData)
.catch(handleError);
对于addRoomData
和addReservationData
函数,您可能需要使用Promise.all() combined with .forEach()
。
如果您想以更易读的方式编写代码,请考虑使用async / await
。
答案 2 :(得分:-1)
我认为更优化的方法是使用 async 模块的 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
});