【问题标题】:Can't promisify callback based function无法承诺基于回调的函数
【发布时间】:2019-12-27 01:48:21
【问题描述】:

我想使用库 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 自动记录响应,并且我在日志中看到了正确的响应。

我怎样才能“等待”这个电话? (即使通过其他方式,如果这个不是“可承诺的”)

【问题讨论】:

  • promisify 需要一个回调,其中第一个参数是错误。
  • a) 确保正确获取方法的 this 上下文 b) 确保该方法符合 nodeback 约定。
  • const getAllHoroscopeAsync = promisify((sign, cb) => { aztroJs.getAllHoroscope(sign, res => { cb(null, res); }); }); 应该可以工作。
  • 您的代码似乎没问题..您如何调用您的句柄方法??

标签: javascript node.js promise node-promisify


【解决方案1】:

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);
});

注意,返回数据的异步函数没有返回错误的方法是不寻常的,因此aztroJs.getAllHoroscope() 接口在这方面似乎有点可疑。

实际上,如果您查看code for this function,您可以看到它正在使用request() 库发出网络请求,然后在出现错误时尝试在异步回调中使用throw。这是一个完全有缺陷的设计,因为您(作为调用者)无法捕获异步抛出的异常。所以,这个包没有合理的方式来反馈错误。设计的很差。

【讨论】:

    【解决方案2】:

    尝试自定义promisified函数

    aztroJs.getAllHoroscope[util.promisify.custom] = (sign) => {
      return new Promise((resolve, reject) => {
        aztroJs.getAllHoroscope(sign, resolve);
      });
    };
    
    const getAllHoroscopeAsync = util.promisify(aztroJs.getAllHoroscope);
    

    【讨论】:

      【解决方案3】:

      您可以将 getAllHoroscopeAsync 更改为 promise 函数

      例子:

      const getAllHoroscopeAsync = (sign) => 
          new Promise(resolve => 
                  aztroJs.getAllHoroscope(sign, (res) => resolve(res)));
      

      【讨论】:

        猜你喜欢
        • 2018-03-27
        • 2015-08-13
        • 1970-01-01
        • 2016-06-15
        • 2019-01-15
        • 2017-07-20
        • 2016-10-24
        • 1970-01-01
        相关资源
        最近更新 更多