带有请求承诺的异步/等待返回未定义

Posted

技术标签:

【中文标题】带有请求承诺的异步/等待返回未定义【英文标题】:Async/Await with Request-Promise returns Undefined 【发布时间】:2018-04-30 16:43:03 【问题描述】:

我有两个文件; server.js 和 scrape.js,下面是他们目前的代码 sn-ps。

server.js:

const scrape = require("./scrape");

async function start() 
    const response = await scrape.start();
    console.log(response);


start();

和scrape.js:

const cheerio = require("cheerio");
const request = require("request-promise");

go = async () => 

const options = 
  uri: "http://www.somewebsite.com/something",
  transform: function(body) 
    return cheerio.load(body);
  
;

request(options)
  .then($ => 
    let scrapeTitleArray = [];
    $(".some-class-in-html").each(function(i, obj) 
      const data = $(this)
        .text()
        .trim();
      scrapeTitleArray.push(data);
    );
    return scrapeTitleArray;
  )
  .catch(err => 
    console.log(err);
  );
;

module.exports = 
  start: go
;

所以当我启动 server.js 时,我将 undefined 返回到 console.log(response),当我实际上想要返回我一直推送到的数组时,你能看到我哪里出错了吗?

【问题讨论】:

不应该“去”返回一个承诺吗? @McMurphy 如果我没记错的话,将其声明为异步函数会自动返回一个承诺? .each() 使用“回调”。您需要将其包装在一个承诺中并解决它的结果。否则代码直接跳到返回空数组。您当然需要return request 结果,但如果您不尊重回调,那么您仍然会遇到问题。 go 是一个implicitly global variable。不要那样做。 为什么你将go定义为async函数却没有使用await 【参考方案1】:

你需要 return 来自你的 async 函数的东西(a 内的 return 不会从 main 函数返回)。无论是承诺还是您await-ed。

另外,请务必声明您的 go 变量以避免将其泄漏到全局空间中。

const go = async () => 

  const options = 
    uri: "http://www.somewebsite.com/something",
    transform: function(body) 
      return cheerio.load(body);
    
  ;

  return request(options)
    .then($ => 
      let scrapeTitleArray = [];
      $(".some-class-in-html").each(function(i, obj) 
        const data = $(this)
          .text()
          .trim();
        scrapeTitleArray.push(data);
      );
      return scrapeTitleArray;
    )
    .catch(err => 
      console.log(err);
    );
;

由于您使用的是async 函数,您可能还想利用await 语法。

const go = async () => 

  const options = 
    uri: "http://www.somewebsite.com/something",
    transform: function(body) 
      return cheerio.load(body);
    
  ;

  try 
    const $ = await request(options);
    $(".some-class-in-html").each(function(i, obj) 
      const data = $(this)
        .text()
        .trim();
      scrapeTitleArray.push(data);
    );
    return scrapeTitleArray;
  
  catch (err) 
    console.log(err);
  
;

【讨论】:

.each() 有回调不是吗? @NeilLunn 是的.each 使用同步回调(所以这里可以使用)。 So it is @NeilLunn(当然map 应该优先于each+push【参考方案2】:

我相信您的 go 函数没有返回任何值。

您正在调用request(options).then(...),但go 永远不会返回该承诺的后续内容。我建议你添加一个return 声明:

go = async () => 

  const options = 
    uri: "http://www.somewebsite.com/something",
    transform: function(body) 
      return cheerio.load(body);
    
  ;

  // The only difference is that it says "return" here:
  return request(options)
    .then($ => 
      let scrapeTitleArray = [];
      $(".some-class-in-html").each(function(i, obj) 
        const data = $(this)
          .text()
          .trim();
        scrapeTitleArray.push(data);
      );
      return scrapeTitleArray;
    )
    .catch(err => 
      console.log(err);
    );
;

【讨论】:

以上是关于带有请求承诺的异步/等待返回未定义的主要内容,如果未能解决你的问题,请参考以下文章

在自定义承诺上使用异步等待

在自定义承诺上使用异步等待

等待/异步如何处理未解决的承诺

在返回承诺的函数上使用 .success 时,未定义不是函数

测试 redux thunk 异步操作给出未定义而不是承诺

等待将undefined返回到异步函数(var all_courses未定义)