【问题标题】:How to correctly use 'async, await and promises' in nodejs, while allocating values to a variable returned from a time-consuming function?如何在nodejs中正确使用'async,await和promises',同时将值分配给从耗时函数返回的变量?
【发布时间】:2021-05-30 23:09:43
【问题描述】:

问题陈述:

  • 我们的目标是在数组ytQueryAppJs 中分配值,这些值是从耗时函数httpsYtGetFunc() 返回的。
  • ytQueryAppJs 中的值需要在代码的后续部分中多次使用,因此需要在代码继续执行之前完成“填充”。
  • 还有很多其他数组,比如ytQueryAppJs,其中一个是ytCoverAppJs,需要赋值,和ytQueryAppJs一样。
  • ytCoverAppJs 中的值还需要使用来自ytQueryAppJs 的值。因此,我们将非常感谢使用干净代码的解决方案。

(我是一个绝对的初学者。我从未使用过 async、await 或 promises,我不知道正确的使用方法。请指导。)

流程(重点关注):

  • 用户在 index.html 中提交queryValue
  • 一个数组 ytQueryAppJs 根据查询记录在控制台中。

预期登录控制台(类似):

当前登录控制台:


流程(原项目需要):

  • 用户在 index.html 中提交查询。
  • 数组的值ytQueryAppJsytCoverAppJsytCoverUniqueAppJsytLiveAppJsytLiveUniqueAppJs 根据查询记录在控制台中。

要关注的代码,来自“app.js”:

// https://stackoverflow.com/a/14930567/14597561
function compareAndRemove(removeFromThis, compareToThis) {
  return (removeFromThis = removeFromThis.filter(val => !compareToThis.includes(val)));
}

// Declaring variables for the function 'httpsYtGetFunc'
let apiKey = "";
let urlOfYtGetFunc = "";
let resultOfYtGetFunc = "";
let extractedResultOfYtGetFunc = [];


// This function GETs data, parses it, pushes required values in an array.
async function httpsYtGetFunc(queryOfYtGetFunc) {

  apiKey = "AI...MI"
  urlOfYtGetFunc = "https://www.googleapis.com/youtube/v3/search?key=" + apiKey + "&part=snippet&q=" + queryOfYtGetFunc + "&maxResults=4&order=relevance&type=video";

  let promise = new Promise((resolve, reject) => {

    // GETting data and storing it in chunks.
    https.get(urlOfYtGetFunc, (response) => {
      const chunks = []
      response.on('data', (d) => {
        chunks.push(d)
      })

      // Parsing the chunks
      response.on('end', () => {
        resultOfYtGetFunc = JSON.parse((Buffer.concat(chunks).toString()))
        // console.log(resultOfYtGetFunc)

        // Extracting useful data, and allocating it.
        for (i = 0; i < (resultOfYtGetFunc.items).length; i++) {
          extractedResultOfYtGetFunc[i] = resultOfYtGetFunc.items[i].id.videoId;
          // console.log(extractedResultOfYtGetFunc);
        }
        resolve(extractedResultOfYtGetFunc);
      })
    })
  })
  let result = await promise;
  return result;
}

app.post("/", function(req, res) {

  // Accessing the queryValue, user submitted in index.html. We're using body-parser package here.
  query = req.body.queryValue;

  // Fetching top results related to user's query and putting them in the array.
  ytQueryAppJs = httpsYtGetFunc(query);
  console.log("ytQueryAppJs:");
  console.log(ytQueryAppJs);
});

从 app.js 完成 app.post 方法:

(为了更好地理解问题。)

app.post("/", function(req, res) {

  // Accessing the queryValue user submitted in index.html.
  query = req.body.queryValue;

  // Fetcing top results related to user's query and putting them in the array.
  ytQueryAppJs = httpsYtGetFunc(query);
  console.log("ytQueryAppJs:");
  console.log(ytQueryAppJs);

  // Fetching 'cover' songs related to user's query and putting them in the array.
  if (query.includes("cover") == true) {
    ytCoverAppJs = httpsYtGetFunc(query);
    console.log("ytCoverAppJs:");
    console.log(ytCoverAppJs);
  
    // Removing redundant values.
    ytCoverUniqueAppJs = compareAndRemove(ytCoverAppJs, ytQueryAppJs);
    console.log("ytCoverUniqueAppJs:");
    console.log(ytCoverUniqueAppJs);
  } else {
    ytCoverAppJs = httpsYtGetFunc(query + " cover");
    console.log("ytCoverAppJs:");
    console.log(ytCoverAppJs);
  
    // Removing redundant values.
    ytCoverUniqueAppJs = compareAndRemove(ytCoverAppJs, ytQueryAppJs);

    console.log("ytCoverUniqueAppJs:");
    console.log(ytCoverUniqueAppJs);
  }
  
  // Fetching 'live performances' related to user's query and putting them in the array.
  if (query.includes("live") == true) {
    ytLiveAppJs = httpsYtGetFunc(query);
    console.log("ytLiveAppJs:");
    console.log(ytLiveAppJs);
  
    // Removing redundant values.
    ytLiveUniqueAppJs = compareAndRemove(ytLiveAppJs, ytQueryAppJs.concat(ytCoverUniqueAppJs));

    console.log("ytLiveUniqueAppJs:");
    console.log(ytLiveUniqueAppJs);
  } else {
    ytLiveAppJs = httpsYtGetFunc(query + " live");
    console.log("ytLiveAppJs:");
    console.log(ytLiveAppJs);
  
    // Removing redundant values.
    ytLiveUniqueAppJs = compareAndRemove(ytLiveAppJs, ytQueryAppJs.concat(ytCoverUniqueAppJs));

    console.log("ytLiveUniqueAppJs:");
    console.log(ytLiveUniqueAppJs);
  }

  // Emptying all the arrays.
  ytQueryAppJs.length = 0;
  
  ytCoverAppJs.length = 0;
  ytCoverUniqueAppJs.length = 0;
  
  ytLiveAppJs.length = 0;
  ytLiveUniqueAppJs.length = 0;
});

【问题讨论】:

  • 你试过awaithttps.get吗?
  • 不,我没试过。你能指导我如何尝试吗?
  • 像这样 `let promise = await http....
  • @Areg 好的。我是否需要删除let promise = new Promise((resolve, reject) =&gt; {let result = await promise; return result;resolve(extractedResultOfYtGetFunc); 去哪里了?
  • 详细用法看答案

标签: javascript node.js async-await promise get


【解决方案1】:

不幸的是,您可以在发出请求时在 http 模块上使用 async/await。您可以安装和使用 axios 模块。在你的情况下,它会是这样的

const axios = require('axios');

// Declaring variables for the function 'httpsYtGetFunc'
let apiKey = "";
let urlOfYtGetFunc = "";
let resultOfYtGetFunc = "";
let extractedResultOfYtGetFunc = [];


// This function GETs data, parses it, pushes required values in an array.
async function httpsYtGetFunc(queryOfYtGetFunc) {

  apiKey = "AI...MI"
  urlOfYtGetFunc = "https://www.googleapis.com/youtube/v3/search?key=" + apiKey + "&part=snippet&q=" + queryOfYtGetFunc + "&maxResults=4&order=relevance&type=video";

  const promise = axios.get(urlOfYtGetFunc).then(data => {
   //do your data manipulations here
  })
  .catch(err => {
    //decide what happens on error
  })

或者异步等待

const data = await axios.get(urlOfYtGetFunc);

//Your data variable will become what the api has returned

如果您仍想在 async await 上捕获错误,可以使用 try catch

try{
  const data = await axios.get(urlOfYtGetFunc);
}catch(err){
  //In case of error do something
}

【讨论】:

  • 感谢您的及时回复,朋友。 :) 我采用了 try-catch 的方式。现在,所有数组都以正确的顺序记录。但是ytCoverUniqueAppJsytLiveUniqueAppJs 出来是空的。你也可以看看这个吗?
  • 我在这里问过这个问题:stackoverflow.com/q/67767513/14597561。请访问以获得更好的清晰度。
  • 嘿阿雷格。你似乎在第一句话中做了一个类型。 “不幸的是,您可以*使用异步/等待...”另外,请查看@Luke 的回答。他似乎只使用 https.get 做到了。我还没有测试过。
  • @Varun 他没有直接使用异步等待,而是创建了一个包装器承诺,我怀疑这是否能正常工作
【解决方案2】:

我刚刚查看了代码,我认为问题在于您如何处理请求处理程序中的异步代码。您不会在主体中等待对 httpsYtGetFunc 的函数调用的结果,因此当它在承诺完成之前返回时,这就是您获得 Promise {Pending} 的原因。

另一个问题是数组不是extractedResultOfYtGetFunc 未初始化,您可能会访问不存在的索引。向数组中添加项的方法是push

要解决此问题,您需要稍微重构代码。一个可能的解决方案是这样的,

// Declaring variables for the function 'httpsYtGetFunc'
let apiKey = "";
let urlOfYtGetFunc = "";
let resultOfYtGetFunc = "";
let extractedResultOfYtGetFunc = [];

// This function GETs data, parses it, pushes required values in an array.
function httpsYtGetFunc(queryOfYtGetFunc) {
  apiKey = "AI...MI";
  urlOfYtGetFunc =
    "https://www.googleapis.com/youtube/v3/search?key=" +
    apiKey +
    "&part=snippet&q=" +
    queryOfYtGetFunc +
    "&maxResults=4&order=relevance&type=video";

  return new Promise((resolve, reject) => {
    // GETting data and storing it in chunks.
    https.get(urlOfYtGetFunc, (response) => {
      const chunks = [];
      response.on("data", (d) => {
        chunks.push(d);
      });

      // Parsing the chunks
      response.on("end", () => {
        // Initialising the array
        extractedResultOfYtGetFunc = []
        resultOfYtGetFunc = JSON.parse(Buffer.concat(chunks).toString());
        // console.log(resultOfYtGetFunc)

        // Extracting useful data, and allocating it.
        for (i = 0; i < resultOfYtGetFunc.items.length; i++) {
          // Adding the element to the array
          extractedResultOfYtGetFunc.push(resultOfYtGetFunc.items[i].id.videoId);
          // console.log(extractedResultOfYtGetFunc);
        }
        resolve(extractedResultOfYtGetFunc);
      });
    });
  });
}

app.post("/", async function (req, res) {
  query = req.body.queryValue;

  // Fetching top results related to user's query and putting them in the array.
  ytQueryAppJs = await httpsYtGetFunc(query);
  console.log("ytQueryAppJs:");
  console.log(ytQueryAppJs);
});

另一个选择是使用 axios, 这个代码就是,

app.post("/", async function (req, res) {
  query = req.body.queryValue;

  // Fetching top results related to user's query and putting them in the array.
  try{
    ytQueryAppJs = await axios.get(url); // replace with your URL
    console.log("ytQueryAppJs:");
    console.log(ytQueryAppJs);
  } catch(e) {
    console.log(e);
  }

});

使用 Axios 会更快,因为您不需要为所有内容编写 Promise 包装器,这是必需的,因为节点 HTTP(S) 库不支持开箱即用的 Promise。

【讨论】:

  • 谢谢你的回复,哥们。 :) 我选择了 Axios 的方式。首先,我将 try 中的所有 httpsYtGetFunc(query) 替换为 await axios.get(url);。我必须为不同的搜索传递不同的参数,所以我在所有地方都使用了 Axios 的其他语法。代码按预期运行。代码看起来不干净,所以我创建了一个函数来包含这个 Axios 代码,类似于httpsYtGetFunc。现在,所有数组都以正确的顺序记录,但 ytCoverUniqueAppJsytLiveUniqueAppJs 记录为空。我无法弄清楚原因。你能帮忙吗?
  • 你提到extractedResultOfYtGetFunc 没有初始化。我还需要在函数内的任何地方声明它吗?
  • 我在这里问过这个问题:stackoverflow.com/q/67767513/14597561。请访问以获得更好的清晰度。
猜你喜欢
  • 1970-01-01
  • 2021-12-01
  • 2019-03-01
  • 2019-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-06
相关资源
最近更新 更多