首页 > 解决方案 > Node callback style with promisify? "The 'original' argument must be of type function"

问题描述

I'm using util.promisify in a Google Cloud Function to call IBM Watson Text-to-Speech, which returns a callback. My code works but I get an error message:

TypeError [ERR_INVALID_ARG_TYPE]: The "original" argument must be of type function

The documentation says

Takes a function following the common error-first callback style, i.e. taking a (err, value) => ... callback as the last argument, and returns a version that returns promises.

The IBM Watson callback is complicated and I can't figure out how to refactor it into the Node.js callback style. It's working, should I just ignore the error message? Here's my Google Cloud Function:

exports.IBM_T2S = functions.firestore.document('Users/{userID}/Spanish/IBM_T2S_Request').onUpdate((change) => {

    let word = change.after.data().word;
    let wordFileType = word + '.mp3';

    function getIBMT2S(word, wordFileType) {
      const {Storage} = require('@google-cloud/storage');
      const storage = new Storage();
      const bucket = storage.bucket('myProject.appspot.com');
      const file = bucket.file('Audio/Spanish/Latin_America/' + wordFileType);
      var util = require('util');
      var TextToSpeechV1 = require('watson-developer-cloud/text-to-speech/v1');

      var textToSpeech = new TextToSpeechV1({
        username: 'groucho',
        password: 'swordfish',
        url: 'https://stream.watsonplatform.net/text-to-speech/api'
      });

      var synthesizeParams = {
        text: word,
        accept: 'audio/mpeg',
        voice: 'es-LA_SofiaVoice',
      };

      const options = { // construct the file to write
        metadata: {
          contentType: 'audio/mpeg',
          metadata: {
            source: 'IBM Watson Text-to-Speech',
            languageCode: 'es-LA',
            gender: 'Female'
          }
        }
      };

      textToSpeech.synthesize(synthesizeParams).on('error', function(error) {
        console.log(error);
      }).pipe(file.createWriteStream(options))
      .on('error', function(error) {
        console.error(error);
      })
      .on('finish', function() {
        console.log("Audio file written to Storage.");
      });
    };

var passGetIBMT2S = util.promisify(getIBMT2S(word, wordFileType))
passGetIBMT2S(word, wordFileType)
});

标签: javascriptnode.jscallbackes6-promise

解决方案


它正在工作,因为您正在调用getIBMT2S并将返回值传递给util.promisfy而不是函数本身。

这里有几个问题,首先你的getIBMT2S函数看起来不兼容util.promisfy,正如你从文档中强调的那样,兼容的函数应该遵循典型的回调样式签名(getIBMT2S不带回调参数) .

其次,util.promisify期望function- 在您的情况下,您正在传递函数的返回值。如果getIBMT2S更新为支持回调参数,那么正确的用法是

function getIBMT2S(word, wordFileType, cb) {
  ...
  // be sure to invoke cb in here
}
var passGetIBMT2S = util.promisify(getIBMT2S); // <-- don't call getIBMT2S, pass it in directly
passGetIBMT2S(word, wordFileType) // <-- now invoke the wrapped function
  .then(result => console.log('DONE'));
  .catch(e => console.error(e));

推荐阅读