【问题标题】:How to make Asynchronous calls with express and node如何使用 express 和 node 进行异步调用
【发布时间】:2020-04-01 09:02:37
【问题描述】:

我有一个小型应用程序,它询问用户他们所在的城市并返回当前天气数据。当用户单击“获取天气”功能时,它会从 OpenWeatherMap api 中提取 Json 并将其返回给用户。截至目前,它刷新页面并显示数据。我需要更改什么,以便在您更改城市时异步加载而不是刷新页面?

Server.js(快速路由)

const express = require('express');
const bodyParser = require('body-parser');
const weatherFunctions = require('./functions/weatherFunctions.js')
const PORT = process.env.PORT || 5000
const app = express()

app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: true }));
app.set('view engine', 'ejs')

app.get('/', (req, res) => {
    res.render('index', {weather: null, error: null});
})

app.post('/', weatherFunctions.getWeather)

app.listen(PORT, () => console.log(`Listening on ${ PORT }`))

weatherFunctions.js

const request = require('request');
const apiKey = '28af81603ac21f0fe4c75478dad21818';

function currentWeather(req, res) {

    let city = req.body.city;
    let url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&units=imperial&appid=${apiKey}`

    request(url, function (err, response, body) {
        if (err) {
            res.render('index', {
                weather: null,
                error: 'Error, please try again'
            });
        } else {
            let weather = JSON.parse(body)
            if (weather.main == undefined) {
                res.render('index', {
                    weather: null,
                    error: 'Error, please try again'
                });
            } else {
                let weatherText = `It's ${weather.main.temp} degrees in ${weather.name}! `;
                weatherText += `The low for today will be ${weather.main.temp_min} degrees with a high of ${weather.main.temp_max}`;
                res.render('index', {
                    weather: weatherText,
                    error: null
                }); //passes parameters for ejs to read
            }
        }
    });
}




module.exports = {
    getWeather: currentWeather
};

index.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Simple Weather</title>
    <link rel="stylesheet" type="text/css" href="/css/style.css">
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:300' rel='stylesheet' type='text/css'>
  </head>
  <body>
    <div class="container">
      <fieldset>
        <form action="/" method="post">
          <input name="city" type="text" class="ghost-input" placeholder="Enter a City" required>
          <input type="submit" class="ghost-button" value="Get Weather">
        </form>
        <% if(weather !== null){ %>
          <p><%= weather %></p>
        <% } %>

        <% if(error !== null){ %>
          <p><%= error %></p>
        <% } %>
      </fieldset>
    </div>
  </body>
</html>

【问题讨论】:

    标签: javascript node.js ajax express asynchronous


    【解决方案1】:

    它让您耳目一新的原因是因为您正在渲染 HTML 服务器端。您将需要利用XMLHttpRequest (aka XHR)。您可以使用一个名为 fetch 的 XHR 包装器,这使得使用 XHR 变得更加容易。

    使用浏览器获取 API 数据,然后使用该数据修改 DOM,称为“客户端渲染”..

    例如,如果您打开浏览器控制台,并将以下代码粘贴到其中,您将看到如何从浏览器发送请求并取回数据(这是客户端渲染的基础):

    fetch(`https://api.openweathermap.org/data/2.5/weather?q=New York&units=imperial&appid=28af81603ac21f0fe4c75478dad21818`).then(res => res.json()).then(data => console.log(data));
    

    看下面的例子:

    document
      .getElementById("getWeather")
      .addEventListener("click", () => {
        handleGetWeather();
      });
    
    async function handleGetWeather() {
      const apiKey = "28af81603ac21f0fe4c75478dad21818";
      const locationEl = document.getElementById("location");
      const weatherDataEl = document.getElementById("weatherData");
    
      const results = await currentWeather(locationEl.value, apiKey);
      weatherDataEl.innerHTML = results;
    }
    
    async function currentWeather(location, apiKey) {
      const city = location.replace(/\s\s+/g, ' '); // Replace multiple spaces with single space
      if (city === "" || city === " ") return `<pre>Please enter a location!</pre>`;
      let url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=imperial&appid=${apiKey}`;
      try {
        const res = await fetch(url);
        if (res.ok === false) {
          return `<pre><i>Location '${encodeURIComponent(city)}' not found!</i></pre><br/><pre>Full Error: ${res.statusText}</pre>`;
        }
        const weather = await res.json();
        const main = weather.main;
        const t = Number(main.temp) >= 71.00 ? 'hot' : 'cold';
        const min = Number(main.temp_min) >= 71.00 ? 'hot' : 'cold';
        const max = Number(main.temp_max) >= 71.00 ? 'hot' : 'cold';
        return `
          <h1>
            It's <span class="${t}">${main.temp}</span> degrees in ${weather.name}!
          </h1>
          <h1>
            The low for today will be 
            <span class="${min}">${main.temp_min}</span>
            degrees with a high of 
            <span class="${max}">${main.temp_max}</span>
          </h1>
        `;
      } catch {
        return `<pre><i>Error, please try again.</i></pre>`;
      }
    }
    pre {
      color: red;
      margin-bottom: -15px;
    }
    
    .hot {
      color: red;
    }
    
    .cold {
      color: blue;
    }
    <input id="location" />
    <button id="getWeather">Get Weather</button>
    <div id="weatherData"></div>

    【讨论】:

      【解决方案2】:

      快速解答

      您需要使用 javascript 和 ajax(前端)直接从您的页面使用 api.openweathermap 端点,而不是通过您(后端)中的 nodejs

      说明

      在 Web 开发中,有两种方法可以向最终用户提供内容,称为 Server rendering and client side rendering

      服务器端渲染 (SSR) — 传统的渲染方法,基本上您页面的所有资源都存放在服务器上。然后,当页面被请求(通常来自网络浏览器)时,Html、JS 和 CSS 被下载。框架也可以动态地根据后端逻辑创建 html 并最终下载它。

      技术:java、c#、python、nodejs 等

      客户端渲染 (CSR) — 一种更新的渲染方法,它依赖于通过 JavaScript 框架在客户端(浏览器)上执行的 JS。因此,当请求页面时,会下载一个最小的、很少的或空的 index.html、css 和 js。 javascript 负责发送或接收数据并更新页面的最小部分无需刷新整个页面。。最后,当用户单击或触发某些事件时,javascript 将使用异步调用 (ajax) 通常将 数据 发送或接收到 api rest (json)。

      技术:react、angular、vue、aurelia、jquery、纯javascript等


      在您的情况下,您使用的是后端语言 nodejs 和 ejs framework 在后端动态创建 html,换句话说:服务器渲染

      最后,如果您不想要整个页面的刷新效果,您可以在您的 nodejs 应用程序中添加一个 javascript 作为简单资产,以便在您的 index.ejs 和/或底部下载你的

      此 javascript 必须检测到 页面完全加载 才能加载将 javascript 函数绑定到您的 .你可以使用:

      • jquery:
      • XMLHttpRequest
      • 获取
      • axios
      【解决方案3】:

      要在不刷新页面的情况下加载新城市,以下是您要执行的操作的概要:

      1. 在您的页面中连接客户端 Javascript,以便拦截表单提交,而不是让浏览器提交表单。

      2. 通过 Ajax 调用从您的页面 Javascript 将表单发送到您的服务器(可能使用客户端 fetch() 接口。

      3. 更改服务器 POST 处理程序,使其呈现页面的一部分(更改的部分),而不是整个页面。

      4. 在您的 Javascript 中获取 ajax 调用的结果,并使用 DOM 操作将页面的一部分内容替换为新呈现的部分(可能设置页面中特定父对象的 .innerHTML) .

      对于 Ajax 调用的工作方式,您有几种方法。您可以从服务器获取一段呈现的 HTML,然后将该 HTML 插入页面(替换之前的一些 HTML),或者您可以使用 Ajax 调用获取 JSON 数据,然后在浏览器中将其呈现为 HTML,然后插入HTML。您需要模板渲染的客户端版本才能执行第二个选项。


      仅供参考,目前尚不清楚您为什么将“异步”这个词作为您问题的重要组成部分。这里几乎所有的东西都已经是异步的了。即使在当前版本的页面中发布表单已经是异步的,如果您按上述方式更改它,通过 Javascript 发布也将是异步的。

      【讨论】:

        猜你喜欢
        • 2018-03-05
        • 1970-01-01
        • 2019-07-02
        • 1970-01-01
        • 2019-04-01
        • 2015-02-19
        • 1970-01-01
        • 2017-11-14
        • 2016-07-11
        相关资源
        最近更新 更多