这个承诺有什么问题?

bti*_*lly 3 google-sheets node.js google-sheets-api

作为练习,我试图将https://developers.google.com/sheets/api/quickstart/nodejs从回调样式转换为承诺样式,然后使用util.promisify.

一切顺利,直到最终功能。原文是:

function listMajors(auth) {
  const sheets = google.sheets({version: 'v4', auth});
  sheets.spreadsheets.values.get({
    spreadsheetId: '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms',
    range: 'Class Data!A2:E',
  }, (err, res) => {
    if (err) return console.log('The API returned an error: ' + err);
    const rows = res.data.values;
    if (rows.length) {
      console.log('Name, Major:');
      // Print columns A and E, which correspond to indices 0 and 4.
      rows.map((row) => {
        console.log(`${row[0]}, ${row[4]}`);
      });
    } else {
      console.log('No data found.');
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

承诺的版本是:

function listMajors(auth) {
  const sheets = google.sheets({version: 'v4', auth});

  const getValues = util.promisify(sheets.spreadsheets.values.get);
  getValues({
      spreadsheetId: '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms',
      range: 'Class Data!A2:E',
    }).then(function (res) {
      const rows = res.data.values;
      if (rows.length) {
        // Print columns A and E, which correspond to indices 0 and 4.
        rows.map((row) => {
          console.log(`${row[0]}, ${row[1]}`);
        });
      }
    }).catch(err => console.log('The API returned an error: ' + err));
}
Run Code Online (Sandbox Code Playgroud)

原件返回电子表格。承诺的版本说,The API returned an error: TypeError: Cannot read property 'context' of undefined。我无法弄清楚为什么它们不同。

jfr*_*d00 5

您的承诺版本可能丢失了您尝试调用的方法的父对象。

如果你把它改成这个,这个问题应该得到解决:

let values = sheets.spreadsheets.values;
values.getP = util.promisify(sheets.spreadsheets.values.get);
values.getP().then(...);
Run Code Online (Sandbox Code Playgroud)

这里重要的是,当调用你的promisified 版本时,你仍然使用values对象引用,values.getP()以便promisified 函数仍然获得正确的this值。


仅供参考,您可能还可以将正确的对象绑定到该方法:

const getValues = util.promisify(sheets.spreadsheets.values.get).bind(sheets.spreadsheets.values);
Run Code Online (Sandbox Code Playgroud)

下面是一个简单的例子来演示:

let values = sheets.spreadsheets.values;
values.getP = util.promisify(sheets.spreadsheets.values.get);
values.getP().then(...);
Run Code Online (Sandbox Code Playgroud)


这种情况经常出现,最好能方便地使用以下代码片段:

const util = require('util');
if (!util.promisifyMethod) {
    util.promisifyMethod = function(fn, obj) {
         return util.promisify(fn).bind(obj);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,任何时候你想要 promisify 某个对象的方法,你可以使用它:

const getValues = util.promisifyMethod(sheets.spreadsheets.values.get, sheets.spreadsheets.values);
Run Code Online (Sandbox Code Playgroud)