无法承诺基于回调的功能
Can't promisify callback based function
我想使用库 astro-js,其文档中的典型调用如下所示:
const aztroJs = require("aztro-js");
//Get all horoscope i.e. today's, yesterday's and tomorrow's horoscope
aztroJs.getAllHoroscope(sign, function(res) {
console.log(res);
});
出于多种原因,我想以 async/await 风格和杠杆 try/catch 来使用它。所以我尝试这样承诺:
const aztroJs = require("aztro-js");
const {promisify} = require('util');
const getAllHoroscopeAsync = promisify(aztroJs.getAllHoroscope);
async function handle() {
let result, sign = 'libra';
try {
result = await getAllHoroscopeAsync(sign);
}
catch (err) {
console.log(err);
}
console.log("Result: " + result);
}
但是,当我记录结果时,它是未定义的。我知道调用有效,因为库通过 console.log 自动记录响应,并且我在日志中看到正确的响应。
我怎样才能“等待”这个电话? (即使通过其他方式,如果这个不是“可承诺的”)
您可以将 getAllHoroscopeAsync 更改为承诺函数
示例:
const getAllHoroscopeAsync = (sign) =>
new Promise(resolve =>
aztroJs.getAllHoroscope(sign, (res) => resolve(res)));
util.promisify()
期望回调函数接受两个参数,第一个是错误,当没有错误时必须是 null
,当有错误时必须是非空,第二个是值(如果没有错误)。如果回调遵循该特定规则,它只会正确地承诺一个函数。
要解决这个问题,您必须手动承诺您的函数。
// manually promisify
aztroJs.getAllHoroscopePromise = function(sign) {
return new Promise(resolve => {
aztroJs.getAllHoroscope(sign, function(data) {
resolve(data);
});
});
};
// usage
aztroJs.getAllHoroscopePromise(sign).then(results => {
console.log(results);
});
请注意,异步函数 returns 数据没有返回错误的方法是不寻常的,因此 aztroJs.getAllHoroscope()
接口在这方面似乎有点可疑。
事实上,如果您查看 code for this function,您可以看到它正在使用 request()
库发出网络请求,然后尝试在异步回调中 throw
当错误。这是一个完全有缺陷的设计,因为您(作为调用者)无法捕获异步抛出的异常。所以,这个包没有合理的方式来反馈错误。设计的很烂。
尝试自定义 promisified 函数
aztroJs.getAllHoroscope[util.promisify.custom] = (sign) => {
return new Promise((resolve, reject) => {
aztroJs.getAllHoroscope(sign, resolve);
});
};
const getAllHoroscopeAsync = util.promisify(aztroJs.getAllHoroscope);
我想使用库 astro-js,其文档中的典型调用如下所示:
const aztroJs = require("aztro-js");
//Get all horoscope i.e. today's, yesterday's and tomorrow's horoscope
aztroJs.getAllHoroscope(sign, function(res) {
console.log(res);
});
出于多种原因,我想以 async/await 风格和杠杆 try/catch 来使用它。所以我尝试这样承诺:
const aztroJs = require("aztro-js");
const {promisify} = require('util');
const getAllHoroscopeAsync = promisify(aztroJs.getAllHoroscope);
async function handle() {
let result, sign = 'libra';
try {
result = await getAllHoroscopeAsync(sign);
}
catch (err) {
console.log(err);
}
console.log("Result: " + result);
}
但是,当我记录结果时,它是未定义的。我知道调用有效,因为库通过 console.log 自动记录响应,并且我在日志中看到正确的响应。
我怎样才能“等待”这个电话? (即使通过其他方式,如果这个不是“可承诺的”)
您可以将 getAllHoroscopeAsync 更改为承诺函数
示例:
const getAllHoroscopeAsync = (sign) =>
new Promise(resolve =>
aztroJs.getAllHoroscope(sign, (res) => resolve(res)));
util.promisify()
期望回调函数接受两个参数,第一个是错误,当没有错误时必须是 null
,当有错误时必须是非空,第二个是值(如果没有错误)。如果回调遵循该特定规则,它只会正确地承诺一个函数。
要解决这个问题,您必须手动承诺您的函数。
// manually promisify
aztroJs.getAllHoroscopePromise = function(sign) {
return new Promise(resolve => {
aztroJs.getAllHoroscope(sign, function(data) {
resolve(data);
});
});
};
// usage
aztroJs.getAllHoroscopePromise(sign).then(results => {
console.log(results);
});
请注意,异步函数 returns 数据没有返回错误的方法是不寻常的,因此 aztroJs.getAllHoroscope()
接口在这方面似乎有点可疑。
事实上,如果您查看 code for this function,您可以看到它正在使用 request()
库发出网络请求,然后尝试在异步回调中 throw
当错误。这是一个完全有缺陷的设计,因为您(作为调用者)无法捕获异步抛出的异常。所以,这个包没有合理的方式来反馈错误。设计的很烂。
尝试自定义 promisified 函数
aztroJs.getAllHoroscope[util.promisify.custom] = (sign) => {
return new Promise((resolve, reject) => {
aztroJs.getAllHoroscope(sign, resolve);
});
};
const getAllHoroscopeAsync = util.promisify(aztroJs.getAllHoroscope);