I have this code that is part of a small API that I am writing for an NPM module called Poolio. The question I have seems to be a mon question for those supporting error-first callbacks as well as promises- how do we support both while maintaining consisent APIs and consistent return values from the API? For example, if I conditionally return a promise from my API, depending on whether the consumer of my lib provides a callback, that is a little awkward in my opinion.
The consumer of the lib can provide a callback or use the Promise then function, but not both.
Here is a function exported by my lib, that I would like to promisify:
Pool.prototype.any = function (msg, cb) {
var workId = this.counter++;
var self = this;
return new Promise(function (resolve, reject) {
if (typeof cb === 'function') {
self.resolutions.push({
workId: workId,
cb: cb
});
}
else {
self.resolutions.push({
workId: workId,
resolve: resolve,
reject: reject
});
}
if (this.available.length > 0) {
var cp = this.available.shift();
cp.workId = workId;
cp.send(msg);
}
else {
self.msgQueue.push({
workId: workId,
msg: msg
});
}
});
};
my question is - if the user provides a callback function in the original function arguments, how can I resolve the promise without calling 'then'? Sorry it's hard to explain but hopefully you can understand.
also there is this interesting question: Do never resolved promises cause memory leak?
I have this code that is part of a small API that I am writing for an NPM module called Poolio. The question I have seems to be a mon question for those supporting error-first callbacks as well as promises- how do we support both while maintaining consisent APIs and consistent return values from the API? For example, if I conditionally return a promise from my API, depending on whether the consumer of my lib provides a callback, that is a little awkward in my opinion.
The consumer of the lib can provide a callback or use the Promise then function, but not both.
Here is a function exported by my lib, that I would like to promisify:
Pool.prototype.any = function (msg, cb) {
var workId = this.counter++;
var self = this;
return new Promise(function (resolve, reject) {
if (typeof cb === 'function') {
self.resolutions.push({
workId: workId,
cb: cb
});
}
else {
self.resolutions.push({
workId: workId,
resolve: resolve,
reject: reject
});
}
if (this.available.length > 0) {
var cp = this.available.shift();
cp.workId = workId;
cp.send(msg);
}
else {
self.msgQueue.push({
workId: workId,
msg: msg
});
}
});
};
my question is - if the user provides a callback function in the original function arguments, how can I resolve the promise without calling 'then'? Sorry it's hard to explain but hopefully you can understand.
also there is this interesting question: Do never resolved promises cause memory leak?
Share Improve this question edited Sep 9, 2017 at 18:03 Alexander Mills asked Jan 26, 2016 at 7:13 Alexander MillsAlexander Mills 100k166 gold badges536 silver badges913 bronze badges 9-
3
resolving the promise has nothing to do with
then
... a promise can be resolved independent of anythen
callbacks being invoked on it – Jaromanda X Commented Jan 26, 2016 at 7:22 - 1 if there is a then to be called on the promise, then calling resolve from inside the promise should call all attached then's, right? In other words, if there are no thens, then calling resolve should have no effect, but if there are thens, then those thens should be called. My question is how to avoid calling them. – Alexander Mills Commented Jan 26, 2016 at 7:23
- yes, also any then's "attached" after resolution will be called "immediately" (in quotes because it's not that clear cut) – Jaromanda X Commented Jan 26, 2016 at 7:24
-
My question is how to avoid calling them
- ahhh, I see now! Sorry, totally missed the point of your question – Jaromanda X Commented Jan 26, 2016 at 7:25 - if the user provides a callback function, then you are not going to "push" resolve/reject functions into resolutions, so you'll never be able to call resolve anyway – Jaromanda X Commented Jan 26, 2016 at 7:29
3 Answers
Reset to default 2It's actually very straightforward. Only you may have missed it because it's hidden amongst that tangle of code.
Basically you do this:
var promise = new Promise(function (resolve, reject) { /*....*/});
if (typeof cb === 'function') {
promise.then(cb);
} else {
return promise;
}
Actually, it's a pretty mon thing APIs do (mongodb-driver example). Basically, write a private function accepting a callback, write a public function checking for cb and writing it if necessary. Using the code from your github (_any
might need a refactoring, you don't need to check if cb is a function for example and maybe other things too):
// private function
var _any = function(msg, cb) {
if (this.kill) {
console.log('warning: pool.any called on pool of dead/dying workers');
return;
}
debug('current available pool size for pool_id ' + this.pool_id + ' is: ' + this.available.length);
var workId = this.counter++;
if (typeof cb === 'function') {
this.resolutions.push({
workId: workId,
cb: cb
});
} else {
workId = -1;
}
if (this.available.length > 0) {
var cp = this.available.shift();
cp.workId = workId;
cp.send(msg);
} else {
this.msgQueue.push({
workId: workId,
msg: msg
});
}
};
// public exposed function
Pool.prototype.any = function(msg, cb) {
if (typeof cb === 'function') {
// cb is provided, no action is required here
return _any(msg, cb);
}
// no cb, wrap the call inside a Promise and provide a cb
return new Promise(function(resolve, reject) {
_any(msg, function(err, data) {
if (err) reject(err);
else resolve(data);
});
});
}
I think you are trying to do something like this:
function Pool() {
this.counter = 0
this.resolutions = []
this.available = []
this.msgQueue = []
}
Pool.prototype.any = function(msg, cb) {
const self = this;
const regCB = (msg, resolve, reject) => {
const workId = self.counter++;
self.resolutions.push({
workId,
resolve,
reject,
})
if (self.available.length > 0) {
const cp = self.available.shift();
cp.workId = workId;
cp.send(msg);
} else {
self.msgQueue.push({
workId,
msg,
});
}
}
const promise = new Promise((resolve, reject) => {
if (typeof cb === 'function') {
resolve = data => cb(null, data)
reject = err => cb(err, null)
}
regCB(msg, resolve, reject)
resolve(msg)
})
return promise
}
const fnc = (err, data) => {
console.log('fnc', {
data
})
}
const promise = Promise.resolve(3)
const pool = new Pool
pool.any('with_function', fnc)
const poolPromise = pool.any('with_promise')
poolPromise.then((data) => {
console.log('poolPromise', {
data
})
})