-
Notifications
You must be signed in to change notification settings - Fork 632
Description
Originally posted by @callmehiphop
@vkedia @stephenplusplus @lukesneeringer @jgeewax so our typical callback vs. promise convention is pretty simple - omit the callback and you shall receive a promise. I think this is the first API that really complicates this approach.
Consider the following example
database.runTransaction()
.then(transaction => {
return Promise.all([
transaction,
transaction.getRows('Singers')
]);
})
.then([transaction, rows] => {
// do some kind of mutation based on the rows
return transaction.commit();
})
.then(() => {
// do something async/unrelated to the transaction
});
My main issue is that in order to properly retry our transaction here, we would need to capture all functions passed to the promise before transaction.commit()
and retry them in the correct order before allowing any chaining that occurs after to continue. Technically I don't think this is even feasible, but even if it were I think the overall behavior itself is totally unpredictable for our users. Based on this opinion, I think that our traditional approach will not fly here.
That being said, if we were to continue to try and let both callbacks and promises live together within a single method, we need a different way of letting the user tell us that they want promises.
My current suggestion is to let the user return a promise within the callback (like so)
database.runTransaction((err, transaction) => {
if (err) return Promise.reject(err);
// do some transactional based stuff
return transaction.commit();
})
.then(() => {
// transaction is committed, so some other stuff now
});
However after some discussion in my PR, this also may be confusing for the users. So I would like to revisit this specific API since we don't have a precedent for this specific issue.
An idea that we've been kicking around would basically be to not directly support promises in and out of this method, but only in.. This means the code would resemble the following
database.runTransaction((err, transaction) => {
if (err) {
// an error occurred while trying to get/create a session + transaction
}
// do reads/writes/etc. here
// now the user has a choice between using a promise or a callback
// and while this function will be ran multiple times in the event of an aborted error
// commit will not resolve until either a success or final error occurs
transaction.commit()
.then(() => console.log('committed successfully!'))
.catch((err) => console.error(err));
});
At which point if a user doesn't feel that this is the way they want to use Promises, it would be fairly easy to wrap that into something like
function runTransactions() {
return new Promise((resolve, reject) => {
database.runTransaction((err, transaction) => {
if (err) return reject(err);
// do transaction stuff
transaction.commit().then(resolve, reject);
});
});
}