【问题标题】:Wait for pending Promises before rendering the Page在渲染页面之前等待待处理的 Promise
【发布时间】:2021-08-25 15:55:20
【问题描述】:

我目前正在为 node.js 中的 Twitch-Community 开发一个 web 项目。在呈现页面之前,我正在使用 Twitch API 接收个人资料图片并将它们与其他信息一起添加到对象数组中。不幸的是,当页面呈现时,我只会得到一个关于个人资料图片 URL 的未决承诺。在页面呈现近一毫秒后,我得到了关于 PB-Links 的控制台日志,所以它运行得很快,所以在我看来,ajax 没有意义。在脚本继续渲染页面之前是否有可能等到承诺加载完毕?

提前谢谢你

async function getStreamersPB(streamerName){
  var streamer = await twitch.getUsers(streamerName);
  var streamerPBURL = await streamer.data[0].profile_image_url;


  console.log(streamerPBURL);
}

...

router.get('/', (req, res) => {

  var streamer = [];
    con.query("SELECT * FROM xxx",  function (err, result) {
    if (err) {
      console.log(err);
    }
    if (result.length !== 0){
      for (let i = 0; i < result.length; i++) {
        let streamObj = {
          "id": result[i].id,
          "name": result[i].name,
          "website": result[i].website.toLowerCase(),
          "status": result[i].status,
          "rang": result[i].rang,
          "userPB": getStreamersPB(result[i].name)
        }
        console.log(streamObj);
        streamer.push(streamObj);
    }}});

    con.query("SELECT * FROM xxx WHERE xxx = '" + xxx + "'", function (err, result) {
    if (err) {
      console.log(err);
    } if(result.length === 1){
    res.render('home', {
      message: result[0].twitchName,
      userID: result[0].id,
      streamer: streamer
    });

...

这是我的控制台日志:

{
  id: 1,
  name: 'xxx',
  website: 'xxx',
  status: 0,
  rang: 1,
  userPB: Promise { <pending> }
}
https://static-cdn.jtvnw.net/...xxx

【问题讨论】:

  • 您需要等待getStreamersPB。将function (err, result) 标记为async,以便您等待
  • 嘿@slebetman 我将代码更改为(async function (err, result) {await getStreamersPB(result[i].name)}) 现在我正在获取控制台日志userPB: [AsyncFunction: userPB]

标签: javascript node.js express ejs twitch


【解决方案1】:

由于您收到 Dylan 的回答错误,请将 async 添加到第一个 com.query 函数。

router.get('/', async (req, res) => {

  var streamer = [];
    con.query("SELECT * FROM xxx", async function (err, result) {
    if (err) {
      console.log(err);
    }
    if (result.length !== 0){
      for (let i = 0; i < result.length; i++) {
        
        let streamObj = {
          "id": result[i].id,
          "name": result[i].name,
          "website": result[i].website.toLowerCase(),
          "status": result[i].status,
          "rang": result[i].rang
        }

        // getStreamersPB is an asynchronous method which you must await.
        streamObj.userPB = await getStreamersPB(result[i].name);

        console.log(streamObj);
        streamer.push(streamObj);
    }}});

    con.query("SELECT * FROM xxx WHERE xxx = '" + xxx + "'", function (err, result) {
    if (err) {
      console.log(err);
    } if(result.length === 1){
    res.render('home', {
      message: result[0].twitchName,
      userID: result[0].id,
      streamer: streamer
    });

}

【讨论】:

  • 嗨@infinite_verma 非常感谢您的回答!不幸的是,我在这里得到了userPB: undefined 的控制台日志:( 所以这也不起作用
  • @Maggimann 你有没有返回 getStreamersPB() 中的任何内容?您发布的代码不会返回任何内容,只会打印输出,但我认为这只是不完整的示例。如果您的代码真的没有返回任何内容,那么这就是为什么值为undefined。在 javascript 中,默认返回值是 undefined,所以如果一个函数什么都不返回,它将返回 undefined(或者在这种情况下是一个未定义的 Promise)
【解决方案2】:

正如 slebetman 所说,您必须等待异步函数调用,否则您将向您的客户发送待处理的承诺。这是修改后的代码。

router.get('/', (req, res) => {

  var streamer = [];

  // This function has been marked as async so we can use await in it.
  con.query("SELECT * FROM xxx", async function (err, result) {

    if (err) {
      console.log(err);
    }

    if (result.length !== 0) {
      for (let i = 0; i < result.length; i++) {

        let streamObj = {
          "id": result[i].id,
          "name": result[i].name,
          "website": result[i].website.toLowerCase(),
          "status": result[i].status,
          "rang": result[i].rang
        }

        // getStreamersPB is an asynchronous method which you must await.
        streamObj.userPB = await getStreamersPB(result[i].name);

        console.log(streamObj);
        streamer.push(streamObj);
      }
    }

    // I moved this query to inside the callback for the first query
    // to ensure this query happens after the first one. Originally,
    // both `con.query` calls were being invoked at the same time, so
    // there's no garuntee in what order they execute.
    con.query("SELECT * FROM xxx WHERE xxx = '" + xxx + "'", function (err, result) {
      if (err) {
        console.log(err);
      } if (result.length === 1) {
        res.render('home', {
          message: result[0].twitchName,
          userID: result[0].id,
          streamer: streamer
        });
      }
    });

  });

});

【讨论】:

  • 非常感谢,但现在我收到了 SyntaxError:SyntaxError: await is only valid in async functions and the top level bodies of modules 我还尝试将其他函数设置为异步,但后来我得到了结果:userPB: undefined
  • @Maggimann 我更新了答案。我将错误的功能标记为异步。此外,您的第一个代码假设两个 con.query 调用一个接一个地发生。这不是保证,他们的回调可以按任何顺序发生。所以我把第二个con.query 放在第一个con.query 的回调中。在处理异步函数调用(回调或承诺)时,您必须小心哪些订单函数将完成。在获取的数据返回之前,您不想响应 http 请求。
  • 现在我得到了userPB: undefined的控制台日志
【解决方案3】:

我把它修好了!我忘了在我的函数中添加一个 return 语句!

非常感谢大家的回答和帮助!!!

【讨论】:

    【解决方案4】:

    您可以先使用 css 隐藏页面,然后当您的个人资料图片加载后,使用 javascript 更改 css 并显示页面。

    【讨论】:

    • 如果 JavaScript 是客户端,那将起作用……它不是。
    • 感谢您的回答。以我的方式这是不可能的,因为我不想使用 ajax 或类似的东西,因为我正在渲染带有对象的页面。因此,该站点将以不同的方式出现,因为该数组具有更多的对象。
    • 抱歉,我误会了。我认为这是初始页面渲染后图像加载的问题。我没有意识到这是一个异步/等待问题。 slebetman 的评论解释了您的问题。
    • 仍然非常感谢您的回答!检查我对 slebetman 的命令的回答。这也不起作用:(
    • @Maggimann 我用显示 slebetman 评论的代码发布了一个答案。
    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 2020-06-17
    • 2011-06-10
    • 1970-01-01
    • 2017-01-14
    • 1970-01-01
    • 2019-12-31
    • 2013-05-01
    相关资源
    最近更新 更多