Проблема с Node.js Запрос модуля внутри моей собственной функции - PullRequest
0 голосов
/ 17 апреля 2020

У меня есть этот код:

const request = require('request');

let url = "https://api.warframe.market/v1/items";

let options = {json: true};
let item_urls;
//const response;
request(url, options, (error, res, body) => {
    if (error) {
        return  console.log(error)
    };

    if (!error && res.statusCode == 200) {
        console.log(body);
        item_urls = body.payload.items;

    };
});

Он отлично работает и возвращает JSON в переменную item_urls.

Затем я попытался обернуть свою собственную функцию, как итак:

const request = require('request');

let url = "https://api.warframe.market/v1/items";

let options = {json: true};
let item_urls;
//const response;

function getitems(){
request(url, options, (error, res, body) => {
    if (error) {
        return  console.log(error)
    };

    if (!error && res.statusCode == 200) {
        console.log(body);
        item_urls= body.payload.items;

    };
});
};
getitems()

Но это не работает, item_urls оказывается неопределенным. Код идентичен за исключением того, что находится внутри моей функции. В случае, если вам интересно, почему я хочу, чтобы он был заключен в функцию - мне нужно передать ей параметр, но я удалил этот лог c для простоты и демонстрации проблемы.

Спасибо,

РЕДАКТИРОВАТЬ: Дополнительные детали я забыл упомянуть, извините.

Поэтому я запускаю этот код непосредственно в моей IDE строку за строкой и отправляю строки на узел REPL, чтобы я мог проверить код строки построчно линия. Если мы посмотрим на первый блок кода:

Я выделю все это и запустите. Поскольку запрос асинхронный c, я жду, пока он сначала завершится, я знаю, что он завершен, потому что функция обратного вызова выводит тело на консоль, поэтому я жду, пока не увижу, что на консоль выводится множество данных, вот как Я проверяю, команда выполнена успешно. Сразу после строки кода, которая выводит тело на консоль, оно затем выгружает тело в мою переменную. Чтобы убедиться, что это сработало, я набираю item_urls на самом терминале REPL и вижу вывод.

Со вторым блоком кода я открываю новый REPL, чтобы все было чисто. Затем я снова выполняю все строки кода и жду ... Я ожидаю, что вызов asyn c займет несколько секунд для завершения, как первый блок кода. Однако на консоль ничего не выводится. Я жду до 30 секунд (предыдущий блок кода занимал всего около 5 секунд), затем я снова набираю item_urls на терминале REPL, и он говорит undefined.

Я убежден, что это как-то связано с asyn c и обратный вызов, но я не могу понять, что.

1 Ответ

1 голос
/ 17 апреля 2020

Вы должны использовать item_urls ВНУТРИ обратного вызова, в котором вы впервые получаете его значение. Единственный способ использовать это значение - использовать его прямо в самом обратном вызове или в функции, которую вы вызываете оттуда, и передать ему значение.

Проблема в том, что request() является асинхронным и не блокировки. Это означает, что вы выполняете request(), он запускает операцию, а затем возвращается и переходит к выполнению большего количества кода (включая код, в котором вы пытаетесь использовать item_urls). Но в этот момент обратный вызов еще не был вызван, поэтому он все еще undefined.

В конце, ЕДИНСТВЕННОЕ место, которое, как вы знаете, имеет значение item_urls, находится внутри этого обратного вызова. Таким образом, любой код, который использует это значение, должен go внутри этого обратного вызова или вызываться из этого обратного вызова. Вот как работает асинхронное программирование в node.js.

Итак, оно должно выглядеть следующим образом:

function getitems(){

    request(url, options, (error, res, body) => {
        if (error) {
            return  console.log(error)
        }

        if (!error && res.statusCode == 200) {
            console.log(body);
            // use body.payload.items directly here
            // or call some function here and pass it the value
            // Do not assign it to some higher scoped variable and
            // expect to use it elsewhere.  Can't do that.
        }
    });
}

getitems()

Если вы хотите получить значение вне getitems, тогда вам нужно используйте или обратный вызов, и событие, или обещание для передачи асинхронного полученного значения за пределы getitems(). Вы можете увидеть полное обсуждение того, почему вы не можете просто вернуть значение из getitems() здесь в этом очень популярном ответе: Как я могу вернуть ответ от асинхронного вызова .


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

Вот точная программа, которую я только что выполнил :

const request = require('request');

let url = "https://api.warframe.market/v1/items";

let options = {
    json: true
};
function getitems() {
    request(url, options, (error, res, body) => {
        if (error) {
            return console.log(error);
        }

        if (res.statusCode === 200) {
            console.log(body.payload.items);
        }
    });
}
getitems()

Этот код работает. Это дает мне вывод, как это:

[
  {
    id: '5835a4564b0377e226bdc360',
    url_name: 'axi_c1_intact',
    thumb: 'icons/en/thumbs/Axi_C1_Intact.99413ebefc5b87d57d9e5314265b56de.128x128.png',
    item_name: 'Axi C1 Intact'
  },
  {
    id: '5835a4dd4b0377e226bdc380',
    url_name: 'meso_s3_intact',
    thumb: 'icons/en/thumbs/Meso_S3_Intact.caee59471a7b06ca040f2d257083e008.128x128.png',
    item_name: 'Meso S3 Intact'
  },
  {
    id: '58d8f31c11efe42a5e523215',
    url_name: 'lith_n2_exceptional',
    thumb: 'icons/en/thumbs/Lith_N2_Exceptional.b82a140ba17908be7226fddcecd7bf62.128x128.png',
    item_name: 'Lith N2 Exceptional'
  },
  {
    id: '5936dd6916efa3a742b15f48',
    url_name: 'lith_n3_exceptional',
    thumb: 'icons/en/thumbs/Lith_N3_Exceptional.b82a140ba17908be7226fddcecd7bf62.128x128.png',
    item_name: 'Lith N3 Exceptional'
  },
  {
    id: '5835a4404b0377e226bdc358',
    url_name: 'neo_v4_intact',
    thumb: 'icons/en/thumbs/Neo_V4_Intact.e0e38afae723757487927845b35a81d2.128x128.png',
    item_name: 'Neo V4 Intact'
  },

  .... a whole bunch more items
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...