【问题标题】:How to use async or promises Node/Express如何使用 async 或 Promise Node/Express
【发布时间】:2019-02-16 12:32:21
【问题描述】:

我在这里发布了一个之前的问题,How to fix a race condition in Node.js/Express. Where my console will update correctly but my webpage doesn't update

基本上我想知道如何让我的代码在我的网页更新之前完成加载。我听说承诺或异步工作,但我无法在我的代码中正确使用它们。我在下面制作了我的代码的简单版本。目前,当我加载我的页面时,我的天气功能已正确更新,但我的 flickr API 在显示结果之前需要再加载两次页面。有人可以告诉我如何使用 Async 或 Promises 来加载我的所有数据并立即更新页面吗?

app.get('/', function (req, res) {
  // Render the webpage
  res.render('index', {weather: null, headlocation: null, lat: null, long: null, imgLinks: null, WebLinks: null, imgLinksFl: null, restLat: null, restLong: null, restname: null, error: null});
})

// Main Page
app.post('/', function (req, res) {
  city = req.body.city; // Grab the users input city 
  //console.log(weatherSort); // Debugging
  weatherSearch(); // Openweather API 
  filckrSearch(); // Flickr API

  res.render('index', {weather: weatherText, headlocation: headLocationText, lat: latLocation, long: longLocation, imgLinks: imageLinks, WebLinks: websiteLinks, imgLinksFl: imageLinksFlick, restLat: latitudeRest, restLong: longitudeRest, restname: restName, error: null});

});

// Weather function 
function weatherSearch(){

  // API URL
  let urlw = `http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${apiKeyWeather}`

  // Send out a request 
  request(urlw, function (err, response, bodyW) {
    // Check for errors
    if(err || (JSON.parse(bodyW).cod == '404') || (JSON.parse(bodyW).cod == '401')){
      // If errors are found initialize all variables to empty so that it protects from future errors 
      // in other API functions 

    } else { 
      let weather = JSON.parse(bodyW) // Get JSON result

      weatherText = `It's ${weather.main.temp} degrees in ${weather.name}! ${weatherSort}: ${weatherInfo}`;
      headLocationText = `The City of ${basicLocation}`; 
    }
  });

}

// Flickr API
function filckrSearch(){

  // Create a new Flickr Client 
  var flickr = new Flickr(apiKeyFlickr);
  // Search Flickr based on latitude and longitude of city 
  flickr.photos.search({
    lat: latLocation,
    lon: longLocation,
    radius: 20, // Set radius to 20km 
    sort: flickrsort // Sort the photos by users selection 
  }).then(function (res) {
      var farmid = res.body.photos.photo[0].farm;
  }).catch(function (err) {
    console.error('bonk', err); // Catch errors 
  });
}

【问题讨论】:

    标签: javascript html node.js express ejs


    【解决方案1】:

    这里是您如何“承诺”weatherSearch 的部分示例。另一个的基本想法相同......将它们都包括在内是多余的。

    // Main Page
    app.post('/', async function (req, res) {
      city = req.body.city; // Grab the users input city 
      //console.log(weatherSort); // Debugging
      try {
        let { weatherText, headLocationText } = await weatherSearch(); // Openweather API 
        await filckrSearch(); // <- promisify the same as above
    
        res.render('index', { weather: weatherText, headlocation: headLocationText, lat: latLocation, long: longLocation, imgLinks: imageLinks, WebLinks: websiteLinks, imgLinksFl: imageLinksFlick, restLat: latitudeRest, restLong: longitudeRest, restname: restName, error: null });
      } catch (e) {
        // do something if you get an error
      }
    });
    
    // Weather function 
    function weatherSearch() {
    
      // API URL
      let urlw = `http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${apiKeyWeather}`
    
      // Send out a request 
      return new Promise((resolve, reject) => {
        request(urlw, function (err, response, bodyW) {
          // Check for errors
          if (err || (JSON.parse(bodyW).cod == '404') || (JSON.parse(bodyW).cod == '401')) {
            // If errors are found initialize all variables to empty so that it protects from future errors 
            // in other API functions 
            reject(err);
          } else {
            let weather = JSON.parse(bodyW) // Get JSON result
    
            weatherText = `It's ${weather.main.temp} degrees in ${weather.name}! ${weatherSort}: ${weatherInfo}`;
            headLocationText = `The City of ${basicLocation}`;
            resolve({ weather, weatherText, headLocationText });
          }
        });
      });
    }
    

    基本前提是:

    • 您将带有回调的函数包装在 Promise 中,并在适当的位置调用解析/拒绝函数。
    • 确保返回 Promise
    • 调用时可以使用async/await如上,也可以使用.then().catch()
    • 无论哪种方式,我认为返回所示值而不是在包装闭包中使用全局变量或变量是一种更好的做法。
    • 您可能希望以某种方式捕获任何错误。这样,如果发生问题,它不会使您的 Web 服务器崩溃,并且您还可以根据需要显示或记录错误,并向用户发送您想要的任何错误页面。我的示例展示了 try/catch,它通常与 async/await 一起使用。

    【讨论】:

      【解决方案2】:

      您的weatherSearchflickrSearch 函数都以不同的方式异步执行。 weatherSearch 正在发出网络请求,然后在回调中更新您的文本全局变量。 flickrSearch 也在发出网络请求,但正在通过 Promise API 处理响应。

      您的快速路由代码的问题在于它不是为处理您在weatherSearchflickrSearch 中调用的异步代码而编写的。解决此问题的最简单方法是删除您在函数中更新的全局变量,并让它们返回通过网络请求检索到的值。这是一个简单的例子:

      // Main Page
      app.post('/', async function (req, res) {
      
        const weatherResults = await weatherSearch(); // Here we 'await' the response before rendering the HTML
      
        res.render('index', {
          weather: weatherResults.weatherText, 
          headlocation: weatherResults.headLocationText
        });
      
      });
      
      // Weather function 
      async function weatherSearch() {
        let urlw = `http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${apiKeyWeather}`
        return new Promise(function (resolve, reject) {
          request(url, function (error, res, body) {
            if (err || (JSON.parse(bodyW).cod == '404') || (JSON.parse(bodyW).cod == '401')){
              // This is how the Promise API 'returns' an error on failure
              reject(); 
            }
            else { 
              let weather = JSON.parse(bodyW)
              // This is how the Promise API 'returns' a value on success
              resolve({
                weatherText: `It's ${weather.main.temp} degrees in ${weather.name}! ${weatherSort}: ${weatherInfo}`,
                headLocationText: `The City of ${basicLocation}`
              })
            }
          });
        });
      }
      

      理解节点中的异步代码非常重要!有很多很棒的关于 Promises、async await 和 callbacks 的文章,你可以用来熟悉它。

      【讨论】:

        【解决方案3】:

        试一试BlueBird真的很容易使用,你会在文档中找到很多例子。

        【讨论】:

          猜你喜欢
          • 2017-10-08
          • 2018-02-21
          • 2020-05-28
          • 2013-07-17
          • 1970-01-01
          • 2019-04-04
          • 2019-04-17
          • 2017-10-26
          • 2020-12-19
          相关资源
          最近更新 更多