for循环之后的语句在for循环运行之前运行

时间:2018-03-03 18:38:57

标签: javascript node.js

为什么在循环完成之前解析objlist。由于for循环是同步的,我希望在for循环完成后运行,但是正在解析带有空对象的列表。

 function myFunction(path,files){
        return new Promise(function(resolve,reject){
            let objlist=[];
            files.forEach(function(file,index){
                console.log(file)
                objlist[index]={};
                fs.stat(path + '\\' + file, function(err,stats){
                    if(err){
                        console.log(err.code)
                        console.log(err)
                        throw err;
                    }
                    if(stats.isDirectory()){
                        objlist[index].file = 'folder'
                    }
                    else if(stats.isFile()){
                        objlist[index].file = 'file'
                    }
                    objlist[index].name = file
                    console.log(objlist[index].name) //gives correct output
                    objlist[index].size = stats.size
                });
            })
            console.log(objlist); //gives list of empty objects
            resolve(objlist);

        });
    }

3 个答案:

答案 0 :(得分:1)

forEach需要一个函数并同步执行它(参见JavaScript, Node.js: is Array.forEach asynchronous?)。 fs.stat是异步的,因此无法保证在调用resolve(objlist)之前所有迭代都会完成。

这是一个建议:

const objlist = await Promise.all(files.map(async file => {
  // return a promise
}))
resolve(objlist)

我喜欢这篇关于promises的文章和ES6的推文:https://developers.google.com/web/fundamentals/primers/promises

感谢https://stackoverflow.com/users/6351322/guijob

的反馈

答案 1 :(得分:0)

fs.stat调用不同步,因为它使用回调。你的forEach循环将启动所有fs.stat进程然后继续,但它不会(也不能让它)等待所有回调在它继续之前被调用。

我认为像下面这样的方法会起作用。 fs-extrafs的优秀版本,bluebird是一个扩展标准Promise的promise库。我不确定是否有必要,你没有说出你正在使用哪个版本的Node;我正在使用它来访问each方法。尝试没有蓝鸟,它可能会工作。

var fs = require('fs-extra');
var Promise = require('bluebird');
global.Promise = Promise;


function myFunction(path,files){
  return Promise
    .each(files, function(file) {
      return fs
        .stat(path + '\\' + file)
        .then(function(stats) {
          var result = {
            name: file,
            size: stats.size
          };
          if ( stats.isDirectory() ) result.file = 'folder';
          if ( stats.isFile() ) result.file = 'file'
          return Promise.resolve(result);
        });
    })
    .tap(console.log)
    .catch(function(err) {
      console.log(err.code);
      console.log(err);
      throw err;
    });
}

答案 2 :(得分:0)

如果您不想使用等待,您可以使用Promise.all或计数器来了解所有fs.stat何时已解决:

仅使用Promise.all

 function myFunction(path,files){
    return Promise.all(files.map(function(file,index){
            console.log(file)
            var obj = {};
            fs.stat(path + '\\' + file, function(err,stats){
                if(err){
                    console.log(err.code)
                    console.log(err)
                    throw err;
                }
                if(stats.isDirectory()){
                    obj.file = 'folder'
                }
                else if(stats.isFile()){
                    obj.file = 'file'
                }
                obj.name = file
                console.log(objlist[index].name) //gives correct output
                obj.size = stats.size
                return obj;
            });
        }))
    .then(objList => {
        console.log(objlist); //gives list of empty objects
        resolve(objlist);
    });
}

或使用计数器:

 function myFunction(path,files){
    return new Promise(function(resolve,reject){
        let objlist=[];
        var counter = files.length;
        files.forEach(function(file,index){
            console.log(file)
            objlist[index]={};
            fs.stat(path + '\\' + file, function(err,stats){
                counter--;
                if(err){
                    console.log(err.code)
                    console.log(err)
                    throw err;
                }
                if(stats.isDirectory()){
                    objlist[index].file = 'folder'
                }
                else if(stats.isFile()){
                    objlist[index].file = 'file'
                }
                objlist[index].name = file
                console.log(objlist[index].name) //gives correct output
                objlist[index].size = stats.size
                if(counter == 0) {
                    console.log(objlist); //gives list of empty objects
                    resolve(objlist);
                }
            });
        })
    });
}