【问题标题】:Why do i get undefined, even when using a promise?为什么我得到未定义,即使使用承诺?
【发布时间】:2018-02-15 21:41:55
【问题描述】:

我正在尝试使用 promise 来调用函数 getTweets。 不使用 AJAX 调用,而是从 1 个 javascript 文件到另一个的简单承诺“调用”。 该功能有效,但我不断得到“未定义”。 我在 stackoverflow 上阅读了几十个问题,并花了几天时间 理解promise,但还是解决不了。

var Twit = require('twit') // Imports the Twitter library
require('dotenv').config() // to get the environment vars into the app
// This is the function:
function getTweets (screen_name) {
  let T = new Twit({ /* <twitter key and token here> */ });
  T.get('statuses/user_timeline', { screen_name: screen_name, count: 3}, function (err, data, response) {
    let myTweets = [];
    for (let i in data) {
      let text = data[i].text; 
      myTweets.push(text); 
    }
    return myTweets;
  })
}
 module.exports.getTweets = getTweets;

这是试图获得推文的承诺:

 var promise = tweets.getTweets('dizid');
 promise.then(
     console.log(myTweets), 
     console.log(err))
 // gives error: promise.then(
 //                      ^
 // TypeError: Cannot read property 'then' of undefined

非常感谢任何帮助。

【问题讨论】:

  • 在您的问题中,顶部缺少某些内容
  • T 是什么? getTweets 函数定义在哪里?
  • 呃,你的getTweets函数没有使用promise,这就是为什么你把返回值当作promise的时候会报错?
  • 你了解(异步)回调是如何工作的吗?你能单独用它们解决你的问题吗?

标签: javascript node.js promise


【解决方案1】:

你的问题是你永远不会从你的 getTweets() 函数返回任何东西,即使它需要返回一个承诺。该函数调用T.get() 并向其传递一个回调函数。你从这个回调函数返回,但这并没有做任何事情,这并不意味着这个值是从getTweets()返回的。

在处理异步调用时,这是一个很常见的错误。需要做的是让 getTweets() 返回一个承诺,该承诺会在应该解决的时候得到解决。
当使用没有实现 promise 接口的异步调用时,你需要用一个新的 promise 包装这个调用。您的 getTweets() 函数应如下所示:

function getTweets (screen_name) {
  let T = new Twit({ /* <twitter key and token here> */ });
  return new Promise(function(resolve, reject) {
    T.get('statuses/user_timeline', { screen_name: screen_name, count: 3}, function (err, data, response) {
      if (err) {
        reject(err); // Reject the promise since there was an error
      } else {
        let myTweets = [];
        for (let i in data) {
          let text = data[i].text; 
          myTweets.push(text); 
        }
        resolve(myTweets); // Resolve the promise with the result
      }
    });
  });
}

不过,Twit API 似乎确实支持 promise 接口,因此您可以使用由 T.get() 创建的 promise,而不是提供回调函数。 HMR 的回答解释了如何做到这一点。

你犯的另一个错误是这段代码:

promise.then(
  console.log(myTweets), 
  console.log(err))

按照您的编写方式,它显示为“运行console.log(myTweets) console.log(err),然后调用promise.then() 并使用结果前者作为第一个参数,后者的 result 作为第二个参数
then() 采用回调函数(根据 promise 的解析/拒绝调用)作为参数,所以代码应该是这样的:

promise.then(
  function(myTweets) { 
    console.log(myTweets);
  },
  function(err) { 
    console.log(err);
  });

异步/等待

如果您有兴趣更进一步,使用异步代码的现代方法是 async/await,它是 Promise 的语法糖,可让您编写更类似于常规同步代码的异步代码。

标记为async 的函数将隐式返回一个promise,但您编写它时就像返回一个常规值一样。在 async 函数中使用 await 关键字将隐式等待 promise 解析并解开解析的值。这样做的主要实际好处是您可以在循环中使用异步调用并使用常规 try-catch 块处理错误。你的getTweets() 函数使用async/await 看起来像这样:

async function getTweets(screen_name) {
  let T = new Twit({ /* <twitter key and token here> */ });
  const data = await T.get('statuses/user_timeline', { screen_name: screen_name, count: 3});
  // Let's also use map() instead of a for loop
  let myTweets = data.map(function(item) { return item.text; });
  return myTweets;
}

【讨论】:

  • 虽然在技术上是正确的答案(和 +1),但@HMR 的答案提供了更简单的方法,这是基于T.get 在没有回调的情况下调用时已经可以返回一个承诺的事实。因此,手动承诺它可能被认为是不必要的。
  • @WiktorZychla 我知道,这就是为什么我提到 HMR 的答案,而不是仅仅重申同一件事。我的回答的重点是提供更多关于承诺如何工作的一般解释,以帮助更好地理解它们,因为这似乎是 OP 想要的。
  • @MikaelLennholm 非常感谢您的解释。这也让我走上了正确的道路,我相信我最终会让它发挥作用,至少我了解正在发生的事情以及这些方法之间的差异。现在,我得到“ReferenceError: myTweets is not defined”,但我确信我可以解决这个问题。
  • 解决了!经过一个多星期的困惑,明白了,谢谢。也会尝试 async/await 方法!
【解决方案2】:

由于 get 似乎返回 promise,因此您不需要使用回调。获取推文可能如下所示:

//  in getTweets
return T.get(
  'statuses/user_timeline', 
  { screen_name: screen_name, count: 3}
).then(
  function (data) {
    console.log("data:",JSON.stringify(data,undefined,2));
    return data.map(item=>item.text);
  }
)
// exports the function getTweets so that other modules can use it
module.exports.getTweets = getTweets;

如果这不起作用,请告诉我们程序的输出是什么(更新问题)。

您可以像这样调用 getTweets:

tweets.getTweets('dizid')
.then(
  myTweets=>
    console.log(myTweets),
  err=>
    console.log(err)
)

【讨论】:

  • 谢谢@HMR,我会在一大早就开始工作。
  • 再次感谢,这无疑让我走上了正确的道路。当我调用 getTweets 函数时,我得到了很多(原始)推特数据(远不止推特对象),但我可以稍后解决。在(推特数据)输出接近尾声时出现错误:“TypeError:data.map 不是函数”,但我想我也会解决这个问题。这是我最接近解决方案的方法,因此我将其标记为答案。即使花费我几周的时间,我也会继续努力。至少我学到了很多。
【解决方案3】:

我想你忘记了添加功能

promise.then(function(res){
    //code
}

【讨论】:

  • 我会试试你的建议,谢谢。可能需要一段时间,我没那么快。
  • 错误告诉我们这不是代码的问题。
  • 也尝试了你的建议:与上面对@mark的回复相同
【解决方案4】:

你的 .then() 应该包含一个回调函数。

promise.then( res => {
    console.log(res);
});

编辑:我使用 ES6 语法来表示箭头函数,以防你不熟悉。

【讨论】:

  • 我尝试了你的建议,但我仍然收到“TypeError: Cannot read property 'then' of undefined”。我已经测试了我的函数中的代码(只是作为脚本,而不是作为函数)并且有效:我收到了 3 条推文,并且“console.log”验证了这一点。当我将我的“getTweets”代码变成一个函数并尝试从另一个脚本调用该函数时,问题就开始了。我是 JS 和 node 的新手,错误消息也不是很有帮助。
猜你喜欢
  • 2017-07-23
  • 2018-09-27
  • 2018-07-04
  • 2019-02-21
  • 1970-01-01
  • 2021-01-28
  • 2019-10-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多