У меня есть проблема с пониманием того, когда цикл закончен,
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);
});
Вероятно, лучше всего использовать 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
который снова предоставляется обработчикам событий в потоке. Точно так же последний блок получает вывод или ошибку и может снова перейти к вашему методу, чтобы сохранить данные.
Существует небольшое различие в фактическом выполнении вызовов, но в основном применяются те же принципы, что и "сигнальный" вывод, доработавший механизм, обеспечивающий "цикл", так что мы знаем, когда "все" завершены.