最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Push into an array from foreach and make it available outside foreach - Stack Overflow

programmeradmin2浏览0评论

I stuck by looping through an array that receive values from a promise and push values into a new array which is available outside the foreach.

What i have:

   app.post('/submit', function (req, res) {
      uploadPics(req, res, function (err) {
        if (err instanceof multer.MulterError) {
            res.send(JSON.stringify({UploadResult: err.message}));
            console.log(err.message + ' ' +'Redirect /home');
        } else if (err) {
            console.log(err);
        } else {
            res.send(JSON.stringify({UploadResult: 'Success'}));
            var filesarray = req.files;
            var picinfos = [];

            filesarray.forEach(function(file){
                GetFileMetaInfo.filemetainfo(file.path).then(function (metadata){
                    //Stuck here! Can push values into an array (picinfos) but only available in the foreach. not outside..
                })
            })
            //I need picinfos array here....
        }   
    }) 
})

How i receive my metadata:

var exif = require('exif-parser');
var fs = require('fs');


exports.filemetainfo = function (filepath) {
    return new Promise((resolve) => {
        var file = filepath;
        var buffer = fs.readFileSync(file);
        var parser = exif.create(buffer);
        var result = parser.parse();
        resolve (result);
     }).then(function (metadata){
         if (metadata.tags.CreateDate !== undefined){
                date = new Date (metadata.tags.CreateDate*1000);
                datevalues = [
                    date.getFullYear(),
                    date.getMonth()+1,
                    date.getDate(),
                    date.getHours(),
                    date.getMinutes(),
                    date.getSeconds(),
                 ];
                 CreateDate = date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate();
                 CreateTime = date.getHours()+':'+date.getMinutes()+':'+date.getSeconds();
                 console.log("CrDate:" +CreateDate, "CrTime:" +CreateTime );
                } else {
                        console.log("No Metadata Creation Infos found in " +filepath);
                        CreateDate = "";
                        CretaeTime = "";
                }

                if (metadata.tags.GPSLatitude !== undefined){
                    GPSLat = metadata.tags.GPSLatitude;
                    GPSLon = metadata.tags.GPSLongitude;
                    console.log("GPSLat:" + GPSLat , "GPSLon:" +GPSLon); 
                }
                else {
                    console.log("No Metadata GPS Infos found in " +filepath)
                    GPSLat = "";
                    GPSLon = "";
               }
                return MetaData = {
                    GPSLat: GPSLat ,
                    GPSLon: GPSLon,
                    CreateDate: CreateDate,
                    CreateTime: CreateTime,
                    }   
        })
}

May i ask someone to give a hand. How can i make my array available outside the foreach. thank you very much!

I stuck by looping through an array that receive values from a promise and push values into a new array which is available outside the foreach.

What i have:

   app.post('/submit', function (req, res) {
      uploadPics(req, res, function (err) {
        if (err instanceof multer.MulterError) {
            res.send(JSON.stringify({UploadResult: err.message}));
            console.log(err.message + ' ' +'Redirect /home');
        } else if (err) {
            console.log(err);
        } else {
            res.send(JSON.stringify({UploadResult: 'Success'}));
            var filesarray = req.files;
            var picinfos = [];

            filesarray.forEach(function(file){
                GetFileMetaInfo.filemetainfo(file.path).then(function (metadata){
                    //Stuck here! Can push values into an array (picinfos) but only available in the foreach. not outside..
                })
            })
            //I need picinfos array here....
        }   
    }) 
})

How i receive my metadata:

var exif = require('exif-parser');
var fs = require('fs');


exports.filemetainfo = function (filepath) {
    return new Promise((resolve) => {
        var file = filepath;
        var buffer = fs.readFileSync(file);
        var parser = exif.create(buffer);
        var result = parser.parse();
        resolve (result);
     }).then(function (metadata){
         if (metadata.tags.CreateDate !== undefined){
                date = new Date (metadata.tags.CreateDate*1000);
                datevalues = [
                    date.getFullYear(),
                    date.getMonth()+1,
                    date.getDate(),
                    date.getHours(),
                    date.getMinutes(),
                    date.getSeconds(),
                 ];
                 CreateDate = date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate();
                 CreateTime = date.getHours()+':'+date.getMinutes()+':'+date.getSeconds();
                 console.log("CrDate:" +CreateDate, "CrTime:" +CreateTime );
                } else {
                        console.log("No Metadata Creation Infos found in " +filepath);
                        CreateDate = "";
                        CretaeTime = "";
                }

                if (metadata.tags.GPSLatitude !== undefined){
                    GPSLat = metadata.tags.GPSLatitude;
                    GPSLon = metadata.tags.GPSLongitude;
                    console.log("GPSLat:" + GPSLat , "GPSLon:" +GPSLon); 
                }
                else {
                    console.log("No Metadata GPS Infos found in " +filepath)
                    GPSLat = "";
                    GPSLon = "";
               }
                return MetaData = {
                    GPSLat: GPSLat ,
                    GPSLon: GPSLon,
                    CreateDate: CreateDate,
                    CreateTime: CreateTime,
                    }   
        })
}

May i ask someone to give a hand. How can i make my array available outside the foreach. thank you very much!

Share Improve this question edited Dec 17, 2018 at 13:50 Mansour 2044 silver badges12 bronze badges asked Dec 17, 2018 at 12:29 MaikelNightMaikelNight 1332 silver badges9 bronze badges 3
  • What's your node version? (I want to see if you could use arrow functions) – Mansour Commented Dec 17, 2018 at 12:37
  • I use Node.JS v10.14.2 – MaikelNight Commented Dec 17, 2018 at 12:39
  • Then Dinesh answer might be useful :) – Mansour Commented Dec 17, 2018 at 12:40
Add a ment  | 

2 Answers 2

Reset to default 4

The reason you're getting empty array at the end of forEach is because, GetFileMetaInfo.filemetainfo() returns a promise and forEach won't wait for async actions.

You could use async/await with for...of loop to get your desired result.

app.post('/submit', function (req, res) {
  uploadPics(req, res, async function (err) { // note async here
    if (err instanceof multer.MulterError) {
        res.send(JSON.stringify({UploadResult: err.message}));
        console.log(err.message + ' ' +'Redirect /home');
    } else if (err) {
        console.log(err);
    } else {
        res.send(JSON.stringify({UploadResult: 'Success'}));
        var filesarray = req.files;
        var picinfos = [];

        for(let file of filesarray) {
          const metadata = await GetFileMetaInfo.filemetainfo(file.path);
          // push metadata into your array here
          picinfos.push(metadata);
        }

        // You will have picinfos here
    }   
  })
})

Although the question is already answered by Dinesh Pandiyan there are still some adjustments that can be made. The following code in his answer runs sequential, meaning that every async request is made after the previously returned result is resolved.

for(let file of filesarray) {
  const metadata = await GetFileMetaInfo.filemetainfo(file.path);
  //                 ^- pauses the execution of the current running code
  // push metadata into your array here
  picinfos.push(metadata);
}
async call #1 ╌╌await╌╌> async call #2 ╌╌await╌╌> async call #3 ╌╌await╌╌> result

You could make the code concurrent by first executing all async statements and then wait until all results are resolved. This can be done by simply changing the following:

// execute all the async functions first, reducing the wait time

for(let file of filesarray) {
  const metadata = GetFileMetaInfo.filemetainfo(file.path);
  //                 ^- remove the await
  // push metadata into your array here
  picinfos.push(metadata);
}

// wait for all results to be resolved
picinfos = await Promise.all(picinfos);
//           ^- instead await here
async call #1 ╌╌┐
async call #2 ╌╌┼╌╌await all╌╌> result
async call #3 ╌╌┘

The above could be further simplified by simply using an Array.map() in bination with the already shown Promise.all().

var filesarray = req.files;
var picinfos = await Promise.all(filesarray.map(file => {
  return GetFileMetaInfo.filemetainfo(file.path);
}));

// picinfos should be present

Or if you want to avoid working with async/await:

var filesarray = req.files;

Promise.all(filesarray.map(file => {
  return GetFileMetaInfo.filemetainfo(file.path); 
})).then(picinfos => {
  // picinfos should be present
});
发布评论

评论列表(0)

  1. 暂无评论