javascript - NodeJS - 如何使 res.render() 在函数之后运行而不是异步运行

标签 javascript node.js

我制作了一个简单的应用程序,它的 UI 显示一个输入文本和两个按钮:获取和显示。

总体思路是在用户输入一个单词并单击“获取”后 该应用程序将从 Datamuse API 请求 Meaning Like 单词,并以 JSON 格式返回单词及其标签(名词、动词、形容词...)。

我希望如果应用程序成功获取这些单词,那么成功文本将位于名为“fetchStatus”的变量中。

之后,我希望“fetchStatus”的值将在 res.render 中传输到具有 UI 代码的 index.ejs,以便用户可以 查看从 Datamuse 获取是否成功。

运行提取的函数称为“FetchData(req.body.wordInput)”。

问题在于 res.render 函数在 FetchData 函数之前运行,因此 fetchStatus 值为空字符串。

在函数 FetchData 中,我尝试返回字符串并将其传递给 res.render 但没有成功。

如果我将“fetchStatus”作为参数或全局变量,也会发生同样的情况。

app.js
============
//jshint esversion:6

var fetchStatus = "";

var vocabularyTags = {
  syn: {name:"synonym", freq:0},
  n: {name:"noun", freq:0},
  v: {name:"verb", freq:0},
  adj:{name:"adjective", freq:0},
  adv:{name:"adverb", freq:0},
  u:{name:"undetermined", freq:0},
  prop: {name:"propery", freq:0}
};



const express = require("express");
const bodyParser = require("body-parser");
const request = require("request");

var app = express();

// Setting ejs
app.set('view engine', 'ejs');

// Setting body-parser
app.use(bodyParser.urlencoded({ extended: true }));



app.get("/",function(req,res){
  // res.sendFile(__dirname+"/index.html");
  res.render("index", {fetchStatus:"", vocabularyTags:{}});


});

app.post("/",function(req,res){
  // var fetchStatus = "";
  var buttonPressed = req.body.submit;

  if (buttonPressed === "fetch") {
    FetchData(req.body.wordInput);
    console.log("Fetch Status: "+fetchStatus);
    res.render("index",{ fetchStatus:fetchStatus ,vocabularyTags:{} });
  }
  else if (buttonPressed === "show") {
    //ShowData();
    var vocabularyTagsResults = vocabularyTags;
    res.render("index",{fetchStatus:"" ,vocabularyTags:vocabularyTagsResults});

    // Clear Vocabulary Tags Frequencies
    for (var key in vocabularyTags) {
      vocabularyTags[key].freq = 0;
    }



  }

});



app.listen(3000,function(){
  console.log("Server is running on port 3000");
});


function FetchData(wordInput) {
    // var fetchStatus = "";
    var options = {
      url:"https://api.datamuse.com/words",
      method:"GET",
      qs: {
        ml: wordInput
      }
    };

    request(options,function(error,response,body){

      if (error) {
        fetchStatus = error;
      }
      else {
        var dataMuseML = JSON.parse(body);
        console.log(dataMuseML);

        // Counting the related tags
        dataMuseML.forEach(function(item){
          var tags = item.tags;
          tags.forEach(function(tag){
            vocabularyTags[tag].freq++;
          });
        });
        fetchStatus = "Fetch from Datamuse API has succeeded!";
      }
    });

    // return fetchStatus;
}


views/index.ejs
================
<!DOCTYPE html>
<html>

  <head>
    <meta charset="utf-8">
    <title>Datamuse API</title>
  </head>

  <body>
    <h1>Datamuse API</h1>

    <form action="/" method="post">
      <input type="text" name="wordInput" placeholder="Enter a word...">
      <button type="submit" name="submit" value="fetch">Fetch</button>
      <button type="submit" name="submit" value="show">Show</button>
    </form>

    <h3> <%= fetchStatus %> </h3>


    <% for (var key in vocabularyTags) { %>
      <p> <span><%= vocabularyTags[key].name %>:</span> <span> <%= vocabularyTags[key].freq %></span> </p>
    <% } %>


  </body>


</html>

预期结果是“fetchStatus”将有成功或错误文本,因此我可以将其传递给 res.render,这会将其放入 index.ejs 中。

最佳答案

你应该使用Promise来实现

function FetchData(wordInput) {
    // var fetchStatus = "";
    var options = {
      url:"https://api.datamuse.com/words",
      method:"GET",
      qs: {
        ml: wordInput
      }
    };

    return new Promise((resolve, reject) => {
        request(options,function(error,response,body){

          if (error) {
            reject(error);
          }
          else {
            var dataMuseML = JSON.parse(body);
            console.log(dataMuseML);

            // Counting the related tags
            dataMuseML.forEach(function(item){
              var tags = item.tags;
              tags.forEach(function(tag){
                vocabularyTags[tag].freq++;
              });
            });
            resolve("Fetch from Datamuse API has succeeded!");
          }
        });
      });
    // return fetchStatus;
}

然后你可以这样调用它:

app.post("/",function(req,res){
  // var fetchStatus = "";
  var buttonPressed = req.body.submit;

  if (buttonPressed === "fetch") {
    FetchData(req.body.wordInput).then(res => {
      console.log("Fetch Status: "+res);
      res.render("index",{ fetchStatus:res ,vocabularyTags:{} });
    }).catch(err => {
      console.log("Error: "+err);
      res.render("index",{ fetchStatus:err ,vocabularyTags:{} });
    })
  }
  // ...
}

如果您想将结果保留在全局中,您只需设置 fetchStatus,然后调用 resolvethen 即可,如下所示:

// ...
return new Promise((resolve, reject) => {
      if (error) {
        fetchStatus = error;
      }
      else {
        // ...
        fetchStatus = "Fetch from Datamuse API has succeeded!";
      }
    });
  });
  resolve(fetchStatus);
}

app.post("/",function(req,res){
  if (buttonPressed === "fetch") {
    FetchData(req.body.wordInput).then(res => {
      // res or fetchStatus should be available here but it's better to use res
      console.log("Fetch Status: "+res);
      res.render("index",{ fetchStatus:res ,vocabularyTags:{} });
    })
  }
}

关于javascript - NodeJS - 如何使 res.render() 在函数之后运行而不是异步运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57749520/

相关文章:

javascript - 在 ng-repeat 期间添加 Bootstrap 行

javascript - Phonegap 移动应用程序中未定义 Socket.io 变量

javascript - module.exports 中的函数可以访问模块中的全局变量吗?

node.js - 如何解决 : premature close at onclosenexttick in Node. js 服务器?

javascript - 如何在 JavaScript 中包含 TypeScript

javascript - FullCalendar:显示每个事件的总添加时间

javascript - Firebase 和用户个人资料 "Security"

javascript - 在评估方法之外处理来自 puppeteer 页面上下文的事件

javascript - MySQL 和 javascript。似乎无法使用 javascript 更新我的数据库

javascript - HTML5 Canvas 从浏览器缓存加载图像