XMLHTTPRequest внутри цикла forEach не работает - PullRequest
0 голосов
/ 30 августа 2018

Привет! Я пишу короткое приложение node.js, которое отправляет XMLHTTPRequest в API каждый раз, когда выполняет итерации по массиву. Проблема заключается в том, что он продолжает цикл foreach перед возвратом запроса из-за асинхронной природы. Я, наверное, упускаю из виду что-то большое, но большую часть дня я потратил на то, чтобы напрячь свой мозг. Я пытался использовать await безрезультатно, любые решения будут оценены.

Заранее спасибо.

Приложение NODE JS

const mongoose = require("mongoose");
const fs = require("fs");
const ajax = require("./modules/ajax.js");

// Bring in Models
let Dictionary = require("./models/dictionary.js");


//=============================
//     MongoDB connection
//=============================

// Opens connection to database "test"
mongoose.connect("mongodb://localhost/bookCompanion");
let db = mongoose.connection;

// If database test encounters an error, output error to console.
db.on("error", (err)=>{
  console.console.error("Database connection failed.");
});

// Check for connection to the database once.
db.once("open", ()=>{
  console.info("Connected to MongoDB database...");

  fs.readFile("./words.json", "utf8", (err, data)=>{

    if(err){
      console.log(err);
    } else {
      data = JSON.parse(data);
      data.forEach((word, index)=>{

        let search = ajax.get(`LINK TO API?=${word}`);

        search.then((response)=>{

          let newWord = new Dictionary ({
            Word: response.word,
            phonetic: response.phonetic,
            meaning: response.meaning
          }).save();

          console.log(response);

        }).catch((err)=>{
          console.log(err);
        });

      });
    }

  });


});

Модуль XMLHTTPRequest

// Get Request module utilising promises

const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;

const get = (url)=>{
  // This function will return a promise, promises use resolve and reject. The resolve is accessed through .then and the reject through the .catch
  return new Promise((resolve, reject)=>{

    // Create new XMLhttp (AJAX) Request
    let xhr = new XMLHttpRequest();
    // Sets up the request, setting it to a GET request, pointing to the website and setting it to asynchronous
    xhr.open("GET", url , true);
    //sends the request
    xhr.send();

    xhr.onload = ()=>{
      if (xhr.status == 200){
        // When loaded pass the response over to the .then method
        resolve(JSON.parse(xhr.responseText));
      } else {
        // if error pass the status code to the .catch method for error handling
        reject(xhr.statusText);
      }
    };

    xhr.onerror = ()=>{
      // if error pass the status code to the .catch method for error handling
      reject(xhr.statusText && xhr.status);
    };

  });
};

module.exports.get = get;

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Кажется, мой код работает нормально при работе с меньшими массивами, реальная проблема, которую я имею, связана с блокирующей природой цикла forEach и памяти. Массив, который мне нужно перебрать, состоит из более чем 400 000 слов, и приложению не хватает памяти, прежде чем цикл forEach сможет завершиться и освободить стек вызовов для разрешения httprequests.

Любая информация о том, как создать синхронный цикл forEach, который не блокирует стек вызовов, будет принята с благодарностью.

0 голосов
/ 30 августа 2018

Вы должны использовать promise.all , чтобы дождаться выполнения всех обещаний. Promise.all принимает массив обещаний, так как ввод и ожидание ожидают разрешения всех обещаний. Он отклоняется с тем, что если вы используете promise.all, ваш код будет выглядеть примерно так.

const mongoose = require("mongoose");
const fs = require("fs");
const ajax = require("./modules/ajax.js");

// Bring in Models
let Dictionary = require("./models/dictionary.js");


//=============================
//     MongoDB connection
//=============================

// Opens connection to database "test"
mongoose.connect("mongodb://localhost/bookCompanion");
let db = mongoose.connection;

// If database test encounters an error, output error to console.
db.on("error", (err) => {
    console.console.error("Database connection failed.");
});

// Check for connection to the database once.
db.once("open", () => {
    console.info("Connected to MongoDB database...");

    fs.readFile("./words.json", "utf8", (err, data) => {

        if (err) {
            console.log(err);
        } else {
            data = JSON.parse(data);
            var promiseArr = []
            Promise.all(promiseArr.push(
                new Promise((resolve, reject) => {

                    let search = ajax.get(`LINK TO API?=${word}`);

                    search.then((response) => {

                        let newWord = new Dictionary({
                            Word: response.word,
                            phonetic: response.phonetic,
                            meaning: response.meaning
                        }).save();

                        console.log(response);
                        resolve();
                    }).catch((err) => {
                        console.log(err);
                        reject();
                    });

                })
            )).then((response) => {
                //whatever you want to do after completion of all the requests
            })
        }

    });


});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...