簡體   English   中英

如何使用異步或諾言Node / Express

[英]How to use async or promises Node/Express

我在這里發布了先前的問題,即如何解決Node.js / Express中的競爭條件。 我的控制台可以正確更新,但我的網頁無法更新的地方

基本上,我想知道如何在網頁更新之前完成代碼的加載。 我聽說了promise或async的工作,但是我無法在我的代碼中正確使用它們。 我在下面做了一個簡單的代碼版本。 目前,當我加載頁面時,我的天氣功能已正確更新,但是flickr API需要再​​加載兩次頁面才能顯示其結果。 有人可以告訴我如何使用異步或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 
  });
}

這是您如何“承諾” 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中,然后在適當的位置調用resolve / reject函數。
  • 確保您退還承諾
  • 打電話時,可以使用async / await如上,或可以使用.then().catch()
  • 無論哪種方式,我都認為最好返回如圖所示的值,而不是在包裝閉包中使用全局變量或變量。
  • 您可能想以某種方式捕獲任何錯誤。 這樣,如果發生問題,它不會使您的Web服務器崩潰,並且您還可以適當地顯示或記錄錯誤,並向用戶發送所需的任何錯誤頁面。 我的示例顯示了try / catch,通常與async / await一起使用。

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,異步等待和回調的文章很多,您可以用來熟悉它。

試試看, BlueBird真的很容易使用,您會在文檔中找到很多示例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM