Как получить доступ к телу запроса снаружи в асинхронной функции? - PullRequest
0 голосов
/ 16 июня 2019

Итак, у меня есть пост-маршрут, который является функцией асинхронного ожидания, и у меня внутри него есть запрос, который извлекает некоторые данные из API, и я хочу сохранить содержимое этого тела в переменной вне функции запроса

Я пытался использовать обещания, но я не очень знаком с этим.

//@route POST api/portfolio/stock
//@desc Create or update a user's stock portfolio
//@access private
router.post(
  "/stock",
  auth,
  [
    check("symbol", "symbol is require or incorrect.")
      .not()
      .isEmpty(),
    check("qty", "Quantity of the stock purchased is required")
      .not()
      .isEmpty()
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty) {
      return res.status(400).json({ errors: errors.array() });
    }

    const { stock, qty } = req.body;

    const newPortfolio = {};
    newPortfolio.user = req.user.id;
    newPortfolio.stocks = [];
    if(stock) newPortfolio.stocks.stock = stock;
    if(qty) newPortfolio.stocks.qty = qty;

    request(`https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=${stock}&apikey=${config.get(
            "API_KEY")}`, (error, response, body) => {
            if (error) console.error(error);

            if (response.statusCode !== 200) {
                        res.status(404).json({msg: 'No stock found'});
                      }

            let content = JSON.parse(body);
            let quote = content['Global Quote'];
        });

    newPortfolio.stocks.stockInfo = quote;

    try {

        let portfolio = await Portfolio.findOne({ user: user.req.id });

        //update if exists
        if(portfolio) {

            portfolio = await Portfolio.findOneAndUpdate(
                { user: user.req.id },
                { $push: { stocks: newPortfolio.stocks }}
            );

            return res.json(portfolio);

        }

        //create if not found
        portfolio = new Portfolio(newPortfolio);
        await portfolio.save();
        res.json(portfolio);

    } catch (err) {
      console.error(err.message);
      res.status(500).send("Server Error");
    }
  }
);

Я хочу сохранить myPortfolio.stocks.stockInfo, используя тело этого запроса.

1 Ответ

0 голосов
/ 16 июня 2019

Как получить доступ к телу запроса снаружи в асинхронной функции?

Нет.Асинхронные результаты доступны только в асинхронном контексте.Для асинхронной функции, которая возвращает результат через обратный вызов, это означает, что вы потребляете / используете результаты ВНУТРИ обратного вызова.Любой код, которому нужен доступ к этим результатам, отправляется в обратном вызове.В традиционном асинхронном программировании Javascript вы просто продолжаете код своей функции внутри обратного вызова.

К счастью, обещания и изобретение async и await могут сделать кодирование немного проще.Для асинхронных функций, которые возвращают обещание (вместо обратного вызова), вы можете использовать await, чтобы получить их результат, и вы можете написать код, который больше похож на последовательную модель, даже если он все еще асинхронный.

Например, вот как может выглядеть переписывание вашей функции, когда мы переключаем библиотеку запроса-обещания (так же, как библиотека запроса, но возвращает обещание вместо использования обратного вызова), а затем мы используем await для результата:

const rp = require('request-promise');

router.post(
    "/stock",
    auth,
    [
        check("symbol", "symbol is require or incorrect.")
        .not()
        .isEmpty(),
        check("qty", "Quantity of the stock purchased is required")
        .not()
        .isEmpty()
    ],
    async (req, res) => {
        const errors = validationResult(req);
        if (!errors.isEmpty) {
            return res.status(400).json({
                errors: errors.array()
            });
        }

        const {
            stock,
            qty
        } = req.body;

        const newPortfolio = {};
        newPortfolio.user = req.user.id;
        newPortfolio.stocks = [];
        if (stock) newPortfolio.stocks.stock = stock;
        if (qty) newPortfolio.stocks.qty = qty;

        try {
            let body = await rp(`https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=${stock}&apikey=${config.get("API_KEY")}`);
            let content = JSON.parse(body);
            newPortfolio.stocks.stockInfo = content['Global Quote'];
        } catch (e) {
            console.error(e);
            res.status(404).json({
                msg: 'No stock found'
            });
            return;
        }


        try {

            let portfolio = await Portfolio.findOne({
                user: user.req.id
            });

            //update if exists
            if (portfolio) {

                portfolio = await Portfolio.findOneAndUpdate({
                    user: user.req.id
                }, {
                    $push: {
                        stocks: newPortfolio.stocks
                    }
                });

                return res.json(portfolio);

            }

            //create if not found
            portfolio = new Portfolio(newPortfolio);
            await portfolio.save();
            res.json(portfolio);

        } catch (err) {
            console.error(err.message);
            res.status(500).send("Server Error");
        }
    }
);

Примечание: добавление свойств в массив newPortfolio.stocks довольно необычен.Хотя это технически неправильно, вы обычно объявляете newPortfolio.stocks объектом, а не массивом, если вы просто собираетесь добавить к нему свойства и не использовать его как настоящий массив.Люди, которые читают ваш код, часто могут сбить с толку, если вы используете ту же переменную, что и для объекта, и для массива.Обычно вы хотите, чтобы переменная (или свойство) велась как одна или другая, а не как обе.

...