Reputation: 3989
I may be missing something really obvious here, but how do I use util.promisify
with a function which looks like this?
function awkwardFunction (options, data, callback) {
// do stuff ...
let item = "stuff message"
return callback(null, response, item)
}
Which I can call like this:
awkwardFunction ({doIt: true},'some data', (err, result, item) => {
console.log('result')
console.log(result)
console.log('item')
console.log(item)
done()
})
And get back
result
{ data: 'some data' }
item
stuff message
When using the promisified version:
let kptest = require('util').promisify(awkwardFunction)
kptest({doIt: true},'some data')
.then((response, item) => {
console.log('response')
console.log(response)
console.log('item')
console.log(item)
})
.catch(err => {
console.log(err)
})
and trying to access both "response" and "item", it seems the 2nd param is ignored...
result
{ data: 'some data' }
item
undefined
Is there a way to do this WITHOUT changing the function (in reality, it is a library function, so I can't).
Upvotes: 21
Views: 12223
Reputation: 30097
I was just rollling up my sleeves for an open heart surgery to achieve this, but I am glad I found someone has already done this.
If you use Bluebird's Promisify
(it's getting so popular) then there actually is a flag of { multiArgs: true }
that you can pass and will do exactly what you need here! (Source)
It turns multiple arguments of callback into an array. So, in my case for MySQL's query that the default callback has 3 arguments of (error, result, fields)
, getting fields
is not possible with typical promisify. But with that {multiArgs: true}
flag being passed, the resolved value will become an array of [result, fields]
.
Upvotes: 4
Reputation: 3989
I can't decide which approach I like the best - all 3 answers are great. Yury Tarabanko's is probably the most "standard", Alex G's is nicely generic, and estus's super simple.
I don't want to leave this question "Unanswered" because that is not true, and not useful for others looking for the same information.
If there is a better way t handle this, please can the moderators let me know!
Upvotes: 1
Reputation: 222935
util.promisify
is intended to be used with Node-style callbacks with function (err, result): void
signature.
Multiple arguments can be treated manually:
let kptest = require('util').promisify(
(options, data, cb) => awkwardFunction(
options,
data,
(err, ...results) => cb(err, results)
)
)
kptest({doIt: true},'some data')
.then(([response, item]) => {...});
In case more sophisticated functionality is wanted, some third-party solution like pify
can be used instead of util.promisify
, it has multiArgs
option to cover this case.
Upvotes: 29
Reputation: 1917
You could make your own promisify, where you return a promise that resolves with the arguments of the callback and on the then block you destructure them. Hope this helps.
function awkwardFunction (options, data, callback) {
// do stuff ...
let item = "stuff message";
return callback(null, data, item);
}
const mypromisify = (fn) =>
(...args) =>
new Promise(resolve =>
fn(...args,
(...a) => resolve(a)
)
);
const kptest = mypromisify(awkwardFunction);
kptest({ doIt: true }, 'some data')
.then(([error, response, item]) => {
console.log(response);
console.log(item);
})
.catch(err => {
console.log(err);
});
Upvotes: 6
Reputation: 45106
It is not possible to have .then((response, item) => {
because a promise represents single value. But you could have it like this .then(({response, item}) => {
an object w/ two fields.
You'll need to provide a custom promisify implementation for the function.
const { promisify } = require('util')
awkwardFunction[promisify.custom] = (options, data) => new Promise((resolve, reject) => {
awkwardFunction(options, data, (err, response, item) => {
if(err) { reject(err) }
else { resolve({ response, item }) }
})
})
const kptest = promisify(awkwardFunction)
Or if this is the only place where the function is promisified you could use the promisified version directly const kptest = (options, data) => new Promise(...
w/o additional promisification step.
Upvotes: 4