为什么即使在使用承诺时我也未定义?

时间:2018-02-14 17:42:49

标签: javascript node.js promise

我正在尝试使用promise来调用函数getTweets。 不是使用AJAX电话,而是一个简单的承诺'电话'从1个javascript文件到另一个。 该功能有效,但我一直未定义'。 我已经在stackoverflow上阅读了几十个问题并花了好几天时间 理解承诺,但仍然无法解决。

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

非常感谢任何帮助。

4 个答案:

答案 0 :(得分: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()创建的承诺,而不是提供回调函数。 HMR的答案解释了如何做到这一点。

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

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

您编写它的方式,它读取“运行console.log(myTweets) console.log(err),然后使用结果调用promise.then() 前者作为第一个参数,结果后者作为第二个参数
then()将回调函数(根据promise的解析/拒绝而调用)作为参数,因此代码应如下所示:

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

异步/ AWAIT

如果你对进一步的事情感兴趣,使用异步代码的现代方法是async/await,这是promises的语法糖,它允许你编写更类似于常规同步代码的异步代码。

标记为async的函数将隐式返回一个promise,但是您将其写为就像返回常规值一样。在await函数内使用async关键字将隐式等待承诺解析和解包已解析的值。这样做的主要实际好处是,您可以在循环中使用异步调用,并使用常规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 :(得分:0)

由于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)
)

答案 2 :(得分:-1)

我认为你忘了添加功能,如

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

答案 3 :(得分:-2)

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

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

编辑:我使用ES6语法进行箭头功能,以防您对此有所了解。