Задать вопрос
@alexandrtumaykin
PHP-программист

Как сделать запрос синхронным?

Занимаюсь изучением Node и решил начать с koa.
Сейчас пытаюсь решить следующую задачу: нужно реализовать импорт xlsx файла в БД.
Загрузку и чтение файла я реализовал, в процессе импорта нужно добавить проверку корректности данных через доп. запросы к БД и вот здесь возникает сложность. Не могу сообразить как сделать запросы к БД псевдо-синхронными.
Т.е. поэтапно у меня получается следующее:
1. файл загружается на сервер
2. происходит чтение файла
3. через array.map для каждой записи из файла вызывается функция для валидации
4. внутри функции валидации нужно сделать запрос к БД, после выполнения которого продолжить выполнение валидации. И в этом месте загвоздка, т.к. запрос к БД выполняется позже выполнения основного кода.

Пример кода:
function *importExcel() {
  // https://github.com/cojs/busboy
  const parse = require('co-busboy');
  const fs = require('fs');
  const path = require('path');
  const config = require('../../config/path');
  const xlsx = require('xlsx');

  // multipart upload
  let parts = parse(this, {
    checkFile: function (fieldname, file, filename) {
      let ext = path.extname(filename);

      if (ext !== '.xlsx' && ext !== '.xlsm') {
        let err = new Error('Файл должен иметь расширение xlsx либо xlsm');
        err.status = 400;
        return err;
      }
    }
  });

  let part = yield parts;
  let stream = fs.createWriteStream(path.join(config.tmp, Math.random().toString()));
  part.pipe(stream);

  let workBook = yield function (done) {
    stream.on('close', function () {
      try {
        let workBook = xlsx.readFileSync(stream.path);
        done(null, workBook);
      } catch (err) {
        done(err);
      }
    });
  };

  let sheetName = workBook.SheetNames[0];
  let workSheet = workBook.Sheets[sheetName];

  let rows = xlsx.utils.sheet_to_json(workSheet);

  if (rows.length == 0) {
    throw new Error('Импортируемый файл пуст');
  }

  let messages = rows.map((item) => {
    if (Object.keys(item).length > 1) {
      try {
        // ВЫЗОВ ФУНКЦИИ ДЛЯ ПРОВЕРКИ ДАННЫХ В СТРОКЕ ФАЙЛА
        return validateForImport(item);
      } catch (err) {
        return err.message;
      }
    }
    return true;
  }).filter((item) => item !== true);

  this.body = {
    success: true,
    error: messages,
  };

  this.type = 'application/json';
}

/**
 * Валидация для импорта
 *
 * @param data
 * @returns {boolean}
 */
function validateForImport(data) {
  const requiredFields = ['#', 'CID', 'PID', 'Производитель', 'Модель', 'Тип оборудования'];

  requiredFields.forEach((field) => {
    if (data[field] == undefined) {
      let index = field !== '#' ? data['#'] + ': ' : '';
      throw new Error(index + 'колонка "' + field + '" не заполнена');
    }
  });

  let keys = Object.keys(data);
  keys.forEach((field) => {
    data[field] = data[field].trim();
  });
  
  let deviceType;
  // в этом месте нужно сделать запрос к БД и после его выполнения продолжить дальше выполнять функцию
  // выдает ошибку: <b>SyntaxError: Unexpected strict mode reserved word</b>
  // let deviceType = yield db.type.findOne({where: {name: data['Тип оборудования']}});

  // в этом случае данные из БД приходят после отдачи ответа в браузер
  // co(function*() {
  //   return yield db.type.findOne({where: {name: data['Тип оборудования']}});
  // }).then(function (value) {
  //   console.log(value);
  // });

  if (!deviceType) {
    throw new Error(data['#'] + ': тип обородувания "' + data['Тип оборудования'] + '" не найден');
  }

}


Подскажите как грамотнее решить эту задачу.

p.s. используется фреймворк koa и sequelizer для работы с mysql
  • Вопрос задан
  • 1003 просмотра
Подписаться 3 Оценить 5 комментариев
Решения вопроса 1
@alexandrtumaykin Автор вопроса
PHP-программист
Всем спасибо за советы. Подходящим решением оказалось отказаться от Array.map и использовать for для перебора элементов массива.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
eruditecat
@eruditecat
Красноглазик
Изучите, пожалуйста, Promise вот здесь и здесь. Не поленитесь вникнуть в это от и до. Скорей всего, этот инструмент решит Вашу проблему на корню.
Ответ написан
AirWorker
@AirWorker
Node.js full stack web dev
В код особо не вникал, но

// let deviceType = yield db.type.findOne({where: {name: data['Тип оборудования']}});


Вот тут вы пытаетесь использовать генератор в функции не-генераторе:

function validateForImport(data) {

Должно быть как минимум

function* validateForImport(data) {

Вообще в koa все делается просто:

* делаем что-то
var result = yield делаем что-то затычное
* делаем что-то

Когда вызываем что-то через yield - внутри этого что-то можем также вызывать что-то через yield
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы