我有3个函数,我想逐步调用这个函数,例如当我调用第一个函数并得到结果时,我必须调用第二个函数并传递第一次调用返回的参数。在完成第二个调用后,我必须调用第三个函数并传递从第二个函数返回的参数。
#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);
}
}
如何在 NodeJS 中使用 Promise 或 Callback 来实现这个伪代码。我更喜欢使用 Promise。
更新#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);
})
您可以使用
.then
解析一个 Promise,并且可以链接 then
以同步方式解析多个 Promise。
也许这会解决您的用例。
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。
如果作为处理程序传递给 then 的函数返回一个 Promise,则等效的 Promise 将暴露给方法链中后续的 then
参考:答应一切
Promise.all() 方法返回一个单独的 Promise,当可迭代参数中的所有 Promise 都已解析或可迭代参数不包含 Promise 时,该 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 数组,不接受键上带有 Promise 的对象。
# 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)
})
如果您想附加第一个和第二个 Promise 的数据,那么解析那里的 Promise 即可仅在一个位置访问两者的数据。
正如您在评论中提到的,这段代码可能会对您有所帮助。
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) )
由于您的逻辑包含大量用于数据选择和转换的
loop
语句,因此您需要将其重构为:
getCategory(brandId)
.then(addRoomData)
.then(addReservationData)
.then(handleFinalData)
.catch(handleError);
对于
addRoomData
和 addReservationData
函数,您可能需要将 Promise.all() 与 .forEach()
结合使用。
async / await
。
我认为更优化的方法是使用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
});