问题
I am struggling to wrap my head around chaining together promises to achieve a desired result.
Brief background: I'm Using Ionic2 (based on Angular2) to create mobile app. Data persistence is based on SQLite. In order to re-build a complex object that contains nested arrays, I need to chain together a number of database calls.
buildObjectFromID(id) {
return new Promise(function (resolve, reject) {
let db = new DBHelper();
try {
// Get the event object from id
db.getEventWithCMSID(id).then(event => {
db.getBannerForOwner(event.cmsId).then(banner => {
event.banner = banner;
});
db.getImagesForOwner(event.cmsId).then(images => {
event.images = images;
});
db.getProfilePicturesForOwner(event.cmsId).then(profilepictures => {
event.profilepicture = profilepictures;
});
db.getLogosForOwner(event.cmsId).then(logos => {
event.logos = logos;
});
resolve(event);
});
}
catch
(err) {
reject({err: err});
}
}
);
}
This method aims to fetch a main object from the database, and using it's ID, fetches and appends its related properties from additional tables. I wish to rebuild the object in it's entirety before passing the result back.
However, at the moment, the object is passed back and then over time the properties are added once each additional call is completed.
I would really appreciate if someone could inform me how I can chain these together, so that the controller calling 'buildObjectFromID' gets a complete object.
Many thanks.
回答1:
Two changes you can make:
Remember that
then
returns a new promise. Since you already have a promise fromdb.getEventWithCMSID
, you don't need to usenew Promise
at all, just use the one you get from callingthen
on that one. In general, before reaching fornew Promise
, consider whether you already have one the work with.To wait for all of your subordinate operations to complete, use
Promise.all
.
So:
buildObjectFromID(id) {
let db = new DBHelper();
return db.getEventWithCMSID(id).then(event => {
return Promise.all([
db.getBannerForOwner(event.cmsId).then(banner => {
event.banner = banner;
}),
db.getImagesForOwner(event.cmsId).then(images => {
event.images = images;
}),
db.getProfilePicturesForOwner(event.cmsId).then(profilepictures => {
event.profilepicture = profilepictures;
}),
db.getLogosForOwner(event.cmsId).then(logos => {
event.logos = logos;
})
]).then(() => {
return event;
});
});
}
Live Example on Babel's REPL (for brevity I left out two of the subordinate calls, just include banner and images)
That also has the advantage of propagating failures, which your original code didn't do (consider what happens if getBannerForOwner
fails, for instance).
Live Example on Babel's REPL demonstrating failure
回答2:
I would leverage the Promise.all
method and chain different promises like this:
buildObjectFromID(id) {
let db = new DBHelper();
// Get the event object from id
return db.getEventWithCMSID(id).then(event => {
return Promise.all([
event,
db.getBannerForOwner(event.cmsId),
db.getImagesForOwner(event.cmsId),
db.getProfilePicturesForOwner(event.cmsId),
db.getLogosForOwner(event.cmsId)
]);
}).then(result => {
let event = result[0];
let banner = result[1];
let images = result[2];
let logos = result[3];
event.banner = banner;
event.images = images;
event.profilepicture = profilepictures;
event.logos = logos;
return event;
});
}
来源:https://stackoverflow.com/questions/37072571/returning-objects-created-by-chained-javascript-promises