2017-01-25 3 views
2

У меня есть форма, в которой есть поле, которое может загружать несколько изображений в один тег <input>. Когда я обращаюсь к файловой системе с помощью Node, она, похоже, асинхронно ставит очередь на обратный вызов для чтения/записи файлов. Поскольку у меня есть несколько файлов, у меня есть эти вызовы в цикле for, поэтому значение i всегда равно array.length к моменту обратного вызова, в результате чего объект не будет определен.Несколько загрузок файлов в узле, принудительный синхронный обратный вызов?

for (var i = 0; i < req.files.photos.length; i++) { 
    req.fs.readFile(req.files.photos[i].path, function(err, data) { 
     if(err) throw err; 

     // i = req.files.photos.length here 
     // Test is undefined when the breakpoint on this line is hit for the first time 
     var test = req.files.photos[i]; 

     // Both print "undefined" 
     console.log(test.name); 
     console.log(test.originalFileName); 

     var newPath = __dirname + "/../public/uploads/" + req.files.photos[i].name; 

     req.fs.writeFile(newPath, data, function (err) { 
      if (err) throw err; 

      console.log("it worked"); 
     }); 
    }); 
} 

ответ

1

Вы можете использовать IIFE (Сразу Вызываются функция Expression), чтобы захватить правильное значение i во время каждой итерации для цикла:

for (var i = 0; i < req.files.photos.length; i++) { 
    (function(j) { 
     req.fs.readFile(req.files.photos[j].path, function(err, data) { 
      if(err) throw err; 
      var test = req.files.photos[j]; 

      console.log(test.name); 
      console.log(test.originalFileName); 

      var newPath = __dirname + "/../public/uploads/" + req.files.photos[j].name; 

      req.fs.writeFile(newPath, data, function (err) { 
       if (err) throw err; 
       console.log("it worked"); 
      }); 
     }); 
    }(i)); 
} 

немедленного вызова этой функции, значение i будет захвачен по его текущему значению и сохранен в качестве новой ссылки (j) в функции, потому что i является примитивным значением. Это классический пример синтаксиса цепочки и закрытия, есть много примеров в Интернете, если у вас все еще есть проблемы

+1

Спасибо, это разрешило проблему! Я использовал их раньше, когда у меня возникли проблемы с ajax, думаю, я должен держать это в виду в следующий раз :) – James

0

Самый простой способ - это перейти на использование async/await с обещаниями. Если вам нужно делать обе вещи одновременно, вы можете использовать Promise.all.

Требуется небольшая работа, чтобы привыкнуть к обещаниям или настроить с помощью async/await, но это на 100% стоит.

import pify from 'pify'; 
import {readFile, writeFile} from 'fs'; 

const readFilePr = pify(readFile); 
const writeFilePr = pify(writeFile); 

async function copyFiles(req) { 
const {photos} = req.files; 

    for (let photo of photos) { 
    try { 
     const image = await readFilePr(photo.path); 
     const newPath = `${__dirname}/../public/uploads/${photo.name}`; 
     await writeFilePr(newPath);  
    } catch (e) { 
     console.error("Problem copying download: ",e); 
    }  
    } 
} 

Вам может понадобиться настроить babel для всех этого кода на работу (при условии что нет опечаток или что-нибудь, я не проверял).

Смежные вопросы