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

1

У меня есть проблема с пониманием того, когда цикл закончен,

app.post('/api/books', upload.array('images'), function(req, res) {
    let book = req.body.book;
    let arr = [];

    // GridFS get connection with DB   
    var gfs = gridfsstream(conn.db);
    var writestream;

    for (i = 0; i < req.files.length; i++) {
        writestream = gfs.createWriteStream({
            filename: req.files[i].originalname
        });
        fs.createReadStream('uploads/' + req.files[i].filename).pipe(writestream);
        writestream.on("close", function(file) {
            console.log(file.filename + "stored successfully into mongodb using gridfs");
        });
        writestream.on("error", function(file) {
            console.log(file.filename + "not stored into mongodb using gridfs");
        });

        base64(writestream.name, function(response) {
            arr.push(response);
        });
    }

    book.images = arr;
    Book.addBook(book, function(err, book) {
        if (err) {
            throw err;
        }
        res.json(book);
    });
});

Проблема в том, что массив arr пуст, когда я это делаю

book.images = arr 

Мне нужно подождать завершения цикла, но как я могу это сделать?

Я знаю, что это работает, потому что я уже поставил console.log() и работает правильно

base64(writestream.name, function(response) {
    arr.push(response);
});
Теги:
gridfs

1 ответ

2
Лучший ответ

Вероятно, лучше всего использовать Promise.all здесь, но вам нужно обернуть каждый из "файлов" в Promise и вернуть разрешение, основанное на том, когда каждый writeStream завершен или ошибки:

app.post('/api/books', upload.array('images'), function(req,res) {
  let book = req.body.book;
  var gfs = gridfsstream(conn.db);

  Promise.all(
    req.files.map(function(file) => {
      return new Promise(function(resolve,reject) {
        var writestream = gfs.createWriteStream({
          filename: file.originalname
        });

        fs.createReadStream('uploads/'+file.filename).pipe(writestream);

        writestream.on("error",reject);
        writestream.on("close",function() {
           base64(writestream.name, function(response) {
             resolve(response);
           });
        });

      })
    })
  )
  .then(function(images) {
    book.images = images;
    Book.addBook(book,function(err,book) {
      if (err) throw err; // or whatever
      res.json(book)
    });
  })
  .catch(function(err) => {
    // Deal with errors
  });
});

Это не требует дополнительных зависимостей, однако вы можете поочередно использовать async.map в качестве дополнительной зависимости:

app.post('/api/books', upload.array('images'), function(req,res) {
  let book = req.body.book;
  var gfs = gridfsstream(conn.db);

   async.map(
     req.files,
     function(file,callback) {
        var writestream = gfs.createWriteStream({
          filename: file.originalname
        });

        fs.createReadStream('uploads/'+file.filename).pipe(writestream);

        writestream.on("error",callback);
        writestream.on("close",function() {
           base64(writestream.name, function(response) {
             callback(null,response);
           });
        });                      
     },
     function(err,images) {
       if (err) throw err;

       book.images = images;
       Book.addBook(book,function(err,book) {
         if (err) throw err; // or whatever
         res.json(book)
       });
     }
   );
});

Поэтому они выглядят довольно похожими, и в основном они делают то же самое. В каждом случае "loop" теперь является .map() который передает текущее имя файла в качестве аргумента и возвращает массив преобразованного ответа, который в этом случае является результатом функции base64. Ключевым моментом здесь является то, что resolve или callback в основном контролируют ситуацию.

В случае с использованием Promise.all, .map() является базовой функцией JavaScript .map() в массиве, которая по существу возвращает "массив обещаний ", которые реализуют функции reject и resolve которые затем вызываются соответствующие обработчики в потоке.

Здесь "Promises" все выполняются и возвращаются туда, Promise.all в Promise.all и передают выходной массив блоку с .then(), который имеет контент и может затем перейти к вашему методу для обновления/создания, как это может быть,

В примере async.map это скорее использует аргумент callback который снова предоставляется обработчикам событий в потоке. Точно так же последний блок получает вывод или ошибку и может снова перейти к вашему методу, чтобы сохранить данные.

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

  • 0
    Спасибо!!!! работал отлично !!!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню