Reputation: 2346
I have some code that is wrapped in a promise
. This code goes and edits some records in a remote DB and returns with the number of edited records. If the number of edited records is larger than 0
(i.e., some work has been done), then I'd like to run the same method again and again until I get a 0
back (i.e., no more records need editing).
I've tried some different ways, but they all do not terminate (i.e., the resolve is not called) or they don't run properly.
First version I tried:
const doEdits = () => {
return new Promise((resolve, reject) => {
someDB.performEdits()
.then(count => {
if (count > 0) {
doEdits()
} else {
resolve()
}
})
.catch(reject)
})
}
return new Promise((resolve, reject) => {
someDB.init()
.then(doEdits)
.catch(reject)
})
Second version I tried:
const doEdits = () => {
return new Promise((resolve, reject) => {
someDB.performEdits()
.then(count => {
resolve(count)
})
.catch(reject)
})
}
return new Promise((resolve, reject) => {
someDB.init()
.then(doEdits)
.then(count => {
if (count > 0 ) {
return doEdits() // 'doEdits()' did not work...
} else {
resolve()
}
})
.catch(reject)
})
Any and all suggestions are welcome.
Upvotes: 1
Views: 2643
Reputation: 2191
Don't Make Spaghetti
You really shouldn't need to create a bunch of promises, especially since the underlying library you are using is already returning you a promise.This approach should accomplish your goal without all the extra sauce:
const doEdits = count => {
if(count > 0) {
return someDB.performEdits().then(doEdits);
}
};
return someDB.init()
.then(() => {
performEdits().then(doEdits)
});
This will chain the promises from the subsequent db calls to the first promise. Any subsequent then
s (and catch
es) will operate on the returned promise (ie, wait for it to resolve or reject), which will potentially be replaced by a new promise when resolved before being passed to them.
Why your code didn't work
Once you decide you're going to instantiate a Promise, you have taken on the responsibility of handling the resolve and reject callbacks - and committed your self to callback hell. Exactly the kind of thing Promises are supposed to solve.
In both snippets, as soon as you see count > 0
and call into doEdits
, you abandon the previous Promise, instantiate a new one, and end up with a trail of unresolve
d promises in your wake. You would need to pass the resolve and reject functions into the new promise and make sure they get resolved or rejected as appropriate when the new promise resolves or rejects.
Don't Do This
function doEdits(previousPromise) {
someDB.performEdits()
.then((count) => {
if(count > 0) {
doEdits(this);
} else {
resolve();
}
})
};
return new Promise((resolve, reject) => {
someDB.init()
.then(() => {
someDB.performEdits()
.then((count) => {
if(count > 0) {
doEdits(this);
} else {
resolve();
}
})
})
});
Because it's wasteful, and also doesn't handle the case if performEdits iteration 33 rejects. In theory, this might work, but it's a whole lot harder to reason about.
Upvotes: 1
Reputation: 665276
Yes, you were never calling resolve
in the if
branch. But you shouldn't use a resolve
function anyway here, avoid the Promise
constructor antipattern! Just do
function doEdits() {
return someDB.performEdits().then(count => {
if (count > 0) {
return doEdits();
} else {
return undefined; // ???
}
});
}
return someDB.init().then(doEdits);
Upvotes: 3