Node.js - 尝试在回调函数中嵌入回调函数

Node.js - Trying to embed callback function inside a callback function

我有以下代码

const request = require('request');

var url = "https://api.warframe.market/v1/items";

var options = {
  json: true
};
var item_urls;


request(url, options, (error, res, body) => {
  if (error) {
    return console.log(error)
  };

  if (!error && res.statusCode == 200) {

    item_urls = body.payload.items;

    console.log("done");

  };
});

它检索一个 JSON 文件,解析它然后将它保存到 items_urls。它工作正常,没有问题。注意:我通过 IDE 直接在节点 REPL 终端中 运行 宁此代码,以便我可以对其进行调试。在上面执行之后,我然后在终端输入 item_urls 并输出结果。如果您想知道我为什么用 way 来完成它,这个变量稍后将在这个 post 范围之外的另一个函数中使用。我这样做是因为这是我可以将 "request" 的输出保存到变量(接下来解释)的唯一方法。

我有两个问题:

一个是我想把它全部封装成一个函数,但不能让它工作。我希望它作为一个函数,因为稍后我需要从另一个函数调用这段代码。以下是我的更改方式:

const request = require('request');

var url = "https://api.warframe.market/v1/items";

var options = {
  json: true
};
var item_urls;

function test() {
request(url, options, (error, res, body) => {
  if (error) {
    return console.log(error)
  };

  if (!error && res.statusCode == 200) {

    item_urls = body.payload.items;

    console.log("done");

  };
});
}


如您所见,我只将代码的 "request" 部分包装在一个名为 test 的函数中。当我调用此函数 test() 时,它会执行与上面相同的操作并将数据输出到 item_urls。我遇到的问题是我希望函数 return 数据,而不是将其输出到该变量。当我在 REPL 中 运行 test() 时,它显示 undefined。这是预料之中的,因为函数没有 return 任何东西。例如,我想在 运行 var x = test() 时将输出存储在 x 中,但在查看 x 时再次显示未定义。我认为这个问题与我还没有完全掌握的回调有关。

第二个问题是我想要函数内部的 items_url,因为我被告知这样做是最佳做法。

这是我尝试 return 数据的最终代码:

const request = require('request');

var url = "https://api.warframe.market/v1/items";

var options = {
  json: true
};


function test() {
    var item_urls;
request(url, options, (error, res, body) => {
  if (error) {
    return console.log(error)
  };

  if (!error && res.statusCode == 200) {

    item_urls = body.payload.items;

    console.log("done");

  };
});
return item_urls;
}


我将 items_url var 声明移到函数内部,然后使用 return items_url 到 return 它。如果我再 运行 x = test() 它仍然说未定义。我曾尝试将 return 语句移动到不同的代码块,但它从来没有奏效。我究竟做错了什么?我需要它来 return 数据。

有很多方法可以解决这个问题。更好地理解异步编程。

const request = require("request");

var url = "https://api.warframe.market/v1/items";

var options = {
  json: true,
};

function test() {
  var item_urls;
  request(url, options, (error, res, body) => {
    if (error) {
      return console.log(error);
    }
    if (!error && res.statusCode == 200) {
      item_urls = body.payload.items;
      console.log("done");
    }
  });
  // return item_urls;  // WIll return, before even getting data
}

// SOL 1
// USING CALLBACK
function test(cb) {
  request(url, options, (error, res, body) => {
    if (!error && res.statusCode == 200) {
      cb(body.payload.items);
    }
  });
}
test((urls) => {
  console.log(urls);
});

// SOL 2
// USING PROMISE
function test() {
  return new Promise((r, rr) => {
    request(url, options, (error, res, body) => {
      if (error) {
        return rr(error);
      }
      if (!error && res.statusCode == 200) {
        return r(body.payload.items);
      }
    });
  });
}
test().then((urls) => {
  console.log(urls);
});

const {promisify} = require("util")
const pr = promisify(request)
// SOL 3
// USING ASYNC- AWAIT
async function test() {
  const res = await pr(url, options)
  return res.body.payload.items
}
test().then((urls) => {
  console.log(urls);
});