简体   繁体   English

如何使用 express 和 node 进行异步调用

[英]How to make Asynchronous calls with express and node

I have a small application that asks the user for their city and returns current weather data.我有一个小应用程序,它向用户询问他们的城市并返回当前的天气数据。 When the user clicks the "Get Weather" function it pulls the Json from the OpenWeatherMap api and returns it to the user.当用户单击“获取天气”函数时,它会从 OpenWeatherMap api 中提取 Json 并将其返回给用户。 As of right now it refreshes the page and shows the data.截至目前,它会刷新页面并显示数据。 What do I need to change so that instead of a page refresh it loads asynchronously whenever you change the city?我需要更改什么才能在您更改城市时异步加载而不是页面刷新?

Server.js (Express routing) 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天气函数.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索引.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>

The reason it is refreshing for you is because you are rendering HTML server-side.它让您耳目一新的原因是因为您正在呈现 HTML 服务器端。 You will need to take advantage of XMLHttpRequest (aka XHR) .您将需要利用XMLHttpRequest(又名 XHR) You can use an XHR wrapper called fetch which makes working with XHR a lot easier.您可以使用名为fetch的 XHR 包装器,这使得使用 XHR 变得更加容易。

Getting API data using a browser, then modifying the DOM using that data, is known as 'client side rendering'..使用浏览器获取 API 数据,然后使用该数据修改 DOM,称为“客户端渲染”。

For example, if you open up your browsers console, and paste the following code into it, you will see how you can send requests from your browser and get data back (this is the foundation of client side rendering):例如,如果您打开浏览器控制台,并将以下代码粘贴到其中,您将看到如何从浏览器发送请求并获取数据(这是客户端渲染的基础):

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));

See the following example:请参阅以下示例:

 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>

To load a new city without refreshing the page, here's an outline of what you'd do:要在不刷新页面的情况下加载新城市,以下是您要执行的操作的概述:

  1. Hook up client-side Javascript in your page so it intercepts the form submission rather than letting the browser submit the form.在您的页面中连接客户端 Javascript,以便它拦截表单提交,而不是让浏览器提交表单。

  2. Send the form to your server via an Ajax call from your page Javascript (probably using the client-side fetch() interface.通过页面 Javascript 中的 Ajax 调用(可能使用客户端fetch()接口fetch()将表单发送到您的服务器。

  3. Change the server POST handler so that it renders a piece of your page (the piece that changes), not the entire page.更改服务器 POST 处理程序,使其呈现页面的一部分(发生更改的部分),而不是整个页面。

  4. Get the results of the ajax call in your Javascript and replace a portion of the content of the page with the newly rendered portion using DOM manipulations (probably setting the .innerHTML of a particular parent object in your page).在您的 Javascript 中获取 ajax 调用的结果,并使用 DOM 操作(可能设置页面中特定父对象的.innerHTML将页面内容的一部分替换为新呈现的部分。

You have a couple of approaches for how the Ajax call works.对于 Ajax 调用的工作方式,您有几种方法。 You can either a get a piece of rendered HTML from the server and then insert that HTML into the page (replacing some previous HTML) or you can fetch JSON data with the Ajax call and then render that into HTML in the browser and then insert that HTML.您可以从服务器获取一段呈现的 HTML,然后将该 HTML 插入页面(替换一些以前的 HTML),或者您可以使用 Ajax 调用获取 JSON 数据,然后在浏览器中将其呈现为 HTML,然后插入HTML。 You would need a client-side version of your template rendering in order to do the second option.您需要模板渲染的客户端版本才能执行第二个选项。


FYI, it's not clear why you made the word "asynchronous" such a big part of your question.仅供参考,目前尚不清楚您为什么将“异步”一词作为问题的重要组成部分。 Pretty much everything here is already asynchronous.这里几乎所有的东西都已经是异步的。 Even the posting of your form in the current version of your page is already asynchronous and if you change it as above, posting it via Javascript will also be asynchronous.即使您的表单在当前页面版本中的发布已经是异步的,如果您按上述方式更改它,通过 Javascript 发布它也将是异步的。

Quick answer快速回答

You need to consume the api.openweathermap endpoint directly from your page using javascript and ajax (frontrend), rather than through nodejs in your (backend)您需要使用 javascript 和 ajax(前端)直接从您的页面使用api.openweathermap端点,而不是通过您(后端)中的 nodejs

Explanation解释

In web development there are two approaches to deliver content to end users, called Server rendering and client side rendering在 Web 开发中,有两种向最终用户交付内容的方法,称为服务器渲染和客户端渲染

Server side rendering (SSR) — the traditional rendering method, basically all of your page's resources are housed on the server.服务器端渲染 (SSR) — 传统的渲染方法,基本上您页面的所有资源都位于服务器上。 Then, when the page is requested (commonly from web browsers), the Html, JS and CSS are downloaded.然后,当页面被请求时(通常来自 Web 浏览器),Html、JS 和 CSS 被下载。 Also frameworks can dynamically can create the html based on backend logic and finally download it.框架也可以根据后端逻辑动态创建 html 并最终下载它。

Technologies : java, c#, python, nodejs, etc技术:java、c#、python、nodejs等

Client side rendering (CSR) — a more recent kind of rendering method, this relies on JS executed on the client side (browser) via a JavaScript framework.客户端渲染 (CSR) — 一种更新的渲染方法,它依赖于通过 JavaScript 框架在客户端(浏览器)上执行的 JS。 So, when page is requested, a minimal , little or empty index.html, css and js were downloaded.因此,当请求页面时,会下载一个最小的、很少的或空的 index.html、css 和 js。 Here javascript is responsible to send or receive data and update a minimal section of the page without an entire page refresh.这里javascript负责发送或接收数据并更新页面的最小部分,而无需刷新整个页面。 . . Finally when user click or trigger some event, javascript will send or receive the data commonly to an api rest (json) using an async call ( ajax ).最后,当用户单击或触发某个事件时,javascript 将使用异步调用 ( ajax ) 通常将数据发送或接收到 api rest (json)。

Technologies : react, angular, vue, aurelia, jquery, pure javascript, etc技术:react、angular、vue、aurelia、jquery、纯javascript等


In your case you are using nodejs which is a backend language and ejs framework which create dynamically the html in your backend, in other words : Server Rendering在您的情况下,您使用的是后端语言nodejsejs 框架,它在后端动态创建 html,换句话说:服务器渲染

Finally if you don't want the entire page refresh effect, you could add a javascript in your nodejs app as simple asset to download in the of your index.ejs and or at the bottom of your最后,如果你不想要整个页面刷新效果,你可以在你的 nodejs 应用程序中添加一个 javascript 作为简单的资产下载到你的index.ejs和/或在你的底部

This javascript must detect the on page completely loaded to load data of bind a javascript function to your .此 javascript 必须检测完全加载的页面以加载将 javascript 函数绑定到您的 . You could use:你可以使用:

  • jquery :查询:
  • XMLHttpRequest XMLHttpRequest
  • fetch拿来
  • axios公理

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM