Node.js - анализ данных JSON в шаблоны PUG - PullRequest
0 голосов
/ 29 мая 2019

Я пытаюсь разобрать некоторые данные JSON в некоторые элементы, называемые homeCards.Я использую Axios для запроса данных JSON и цикла for для его итерации.Я сохраняю нужные поля в переменных title и description и передаю эти переменные в homeCards.Моя проблема в том, что мои переменные title и description живут внутри моей функции axios, и когда я пытаюсь присвоить эти значения homeCards, которая объявлена ​​вне ее области, она не может их найти.Если я переместлю объявление homeCard в функцию Axios, я не смогу вызвать homeCards в функции рендера внизу файла.Как я могу решить эту проблему?Есть ли гораздо более простой способ сделать это?

var express = require('express');
var router = express.Router();
var title = "title"
var description = "description"

const axios = require('axios');

axios({
  url: "https://api-v3.igdb.com/games",
  method: 'GET',
  headers: {
      'Accept': 'application/json',
      'user-key': 'user-key'
  },
  data: "fields name,summary,popularity;sort popularity desc;limit 4;"
})
  .then(response => {
      let r = response.data;
      for (i=0; i<r.length; ++i){
          title = r[i].name;
          description = r[i].summary;
          console.log(title, description);
      }
    })
  .catch(err => {
      console.error(err);
  });


var homeCards = [
        {
          title: title,
          description: description,
        },
        {
          title: title,
          description: description,
        },
        {
          title: title,
          description: description,
        },
        {
          title: title,
          description: description,
        },
        ]

/* GET home page. */
router.get('/', (req, res, next) => {
  res.render('index', { pageId: 'index',
                        title: 'Homepage',
                        cards: homeCards
    });

});
/*GET consoles page. */
router.get('/consoles', (req, res, next) => {
    res.render('consoles', { pageId:'consoles',
                             title: 'Consoles', });
});
/*GET about page. */
router.get('/about', (req, res, next) => {
    res.render('about', { pageId:'abuot',
                          title: 'About' });
});

module.exports = router;

Если я перемещу соответствующий код в вызовах router.get, например, так:

    /* GET home page. */
router.get('/', (req, res, next) => {
  res.render('index', { pageId: 'index',
                        title: 'Homepage',
                        cards: homeCards
    });

  const axios = require('axios');

  axios({
    url: "https://api-v3.igdb.com/games",
    method: 'GET',
    headers: {
        'Accept': 'application/json',
        'user-key': 'feaa948461a62d2965098834275aaa2f'
    },
    data: "fields name,summary,popularity;sort popularity desc;limit 4;"
  })
    .then(response => {
        let r = response.data;
        for (i=0; i<r.length; ++i){
            title = r[i].name;
            description = r[i].summary;
            console.log(title, description);
        }
      })
    .catch(err => {
        console.error(err);
    });
    var homeCards = [
        {
          title: title,
          description: description,
        },
        {
          title: title,
          description: description,
        },
        {
          title: title,
          description: description,
        },
        {
          title: title,
          description: description,
        },
        ]

});

Я получаю следующую ошибку: index.пуг: 19 17 |div (class = "колода карт") 18 |if pageId === 'index'> 19 |каждый предмет в карточках 20 |+ horizontalCard (item.title, item.imgSrc, item.imgAlt, item.link, item.description) Невозможно прочитать свойство 'длина' из неопределенного.Вот файл мопса, о котором идет речь

 //- views/index.pug
extends layout

mixin horizontalCard(title, imgSrc, imgAlt, link, description)
    div(class="card bg-secondary mb-3" style="min-width: 230px; max-width: 540px;")
        img(src=imgSrc class="card-img" alt=imgAlt)
        div(class="card-body")
            h5(class="card-title")= title
            p(class="card-text")= description
            p(class="card-text")
                small(class="text-muted")
                a(rel="noreferrer noopener" href=link target="_blank") Visit Website

block content
    h1= title
    P Most Popular Games
    div(class="card-deck")
        if pageId === 'index'
            each item in cards
                +horizontalCard(item.title,item.imgSrc, item.imgAlt, item.link, item.description)

Если переместить вызовы router.get в блоке .then (response) следующим образом:

    axios({
  url: "https://api-v3.igdb.com/games",
  method: 'GET',
  headers: {
      'Accept': 'application/json',
      'user-key': 'feaa948461a62d2965098834275aaa2f'
  },
  data: "fields name,summary,popularity;sort popularity desc;limit 4;"
})
  .then(response => {
      /* GET home page. */
    router.get('/', (req, res, next) => {
      res.render('index', { pageId: 'index',
                        title: 'Homepage',
                        cards: homeCards
        });

    });
    var homeCards = [
        {
          title: title,
          description: description,
        },
        {
          title: title,
          description: description,
        },
        {
          title: title,
          description: description,
        },
        {
          title: title,
          description: description,
        },
        ]
    let r = response.data;
    for (i=0; i<r.length; ++i){
        var title = r[i].name;
        var description = r[i].summary;
        console.log(title, description);
      }
    })
  .catch(err => {
      console.error(err);
  });

На домашних картах ничего не отображается

1 Ответ

1 голос
/ 29 мая 2019

В вашем коде блок axios({...}).then() выполняется после основного кода (присвоение homeCards и вызовы router.get).Вот как по дизайну работают асинхронные вызовы Node.js (и JavaScript в целом): axios выполняет сетевой вызов, поэтому возвращает результат в виде обещания, которое разрешается после выполнения кода функции вызывающей стороны.

Перемещение всего, включая вызовы router.get, в обработчик axios .then является одним из вариантов.Другой вариант, если вы нацелены на Node.js 8+, это использовать шаблон async/await для синхронной записи асинхронного кода.По сути, это то же самое, что поместить всю логику в обработчик axios .then, но выглядит намного лучше.

async function init() {
  const response = await axios({...});
  homeCards = ...;
  router.get(...);
  ...
}

init().catch(err => {
  console.error(err);
});
...