Q承诺在lodash中不起作用

时间:2014-05-11 20:03:39

标签: javascript node.js promise q lodash

我正在尝试将文件返回到最早修改日期的目录中。这种方法似乎在createFileDateMap函数中失败了。我想减少一个文件路径数组,并创建一个文件名和模态日期的对象。 getModDate函数是一个异步fs.lstat调用。我似乎无法将我的reducer的acc设置为.then()块中的值。当值依赖于异步调用

时,我不确定如何实现减少
var _ = require('lodash'),
    fs = require('fs'),
    path = require('path'),
    Q = require('q');

function checkDir(dir) {
    // Check if given path is valid directory
    var deferred = Q.defer();
    fs.lstat(dir, deferred.makeNodeResolver());
    return deferred.promise.invoke('isDirectory');
}

function getFiles(dir) {
    // Get all files within a directory
    var deferred = Q.defer();
    fs.readdir(dir, deferred.makeNodeResolver());
    return deferred.promise;
}

function makeFullPathFileArr(dir, files) {
    // Return array of full paths
    return _.map(files, function(file) {
        return path.join(dir, file);
    });
}

function getModDate(file) {
    // Return modification date of file
    var deferred = Q.defer();
    fs.stat(file, deferred.makeNodeResolver());
    return deferred.promise.get('mtime');
}

function createFileDateMap(filesArr) {
    // Return an obj of file paths and modification dates as Date objects
    // {{ file1: Date, file2: Date }}
    var fileDateMap = _.reduce(filesArr, function(acc, file) {
        getModDate(file)
            .then(function(modDate) {
                acc[file] = moment(modDate);
            });
        return acc;
    }, {});
    return fileDateMap;
}

function getMinDateFile(mapObj) {
    // return the file name which has the earliest modification date
    var dates = _.transform(mapObj, function(result, date, key) {
        result[key] = new Date(date);
    });
    var minDate = new Date(Math.min.apply(null, _.values(dates)));
    var invertedMapObj = _.invert(mapObj);

    return invertedMapObj[minDate];
}

var dir = '../reports';
checkDir(dir)
    .then(function(exist) {
        if(exist) {
            getFiles(dir)
                .then(function(fileNames) {
                    return makeFullPathFileArr(dir, fileNames);
                })
                .then(function(fullpathsArr) {
                    return createFileDateMap(fullpathsArr);
                })
                .then(function(fileAndDatesObj) {
                    console.log(getMinDateFile(fileAndDatesObj));
                });
        }
    })
    .catch(function(err) {
        console.log(err);
    });

2 个答案:

答案 0 :(得分:3)

感谢@BenjaminGruenbaum的帮助。 :)

function createFileDateMap(filesArr) {
    // Return an obj of file paths and modification dates as Date objects
    // {{ file1: Date, file2: Date

    return Q.all(_.map(filesArr, getModDate))
        .then(function(modDates) {
           return _.zipObject(filesArr, modDates);
        });
}

答案 1 :(得分:0)

问题是reduce是同步的,并且不知道您在其回调中使用的promise。您将返回fileDateMap,这是一个空对象。这个问题有两种解决方案:

  • 并行调用所有getModDate,使用Q.all获取日期数组的承诺,并在then回调中减少该承诺。

    function createFileDateMap(filesArr) {
        // Return an obj of file paths and modification dates as Date objects
        // {{ file1: Date, file2: Date }}
        return Q.all(_.map(filesArr, function(file) {
            return getModDate(file).then(function(date) {
                return {name:file, date:date};
            });
        })).then(function(fileAndDateArr) {
            return _.reduce(fileAndDateArr, function(acc, o) {
                acc[o.file] = moment(o.date);
                return acc;
            }, {});
        });
    }
    
  • 使acc umlutor成为地图对象的承诺,并通过链接大量then次呼叫来减少“异步”数组。

    function createFileDateMap(filesArr) {
        // Return an obj of file paths and modification dates as Date objects
        // {{ file1: Date, file2: Date }}
        return _.reduce(filesArr, function(acc, file) {
            return acc.then(function(fileDateMap) {
                return getModDate(file).then(function(modDate) {
                    fileDateMap[file] = moment(modDate);
                    return fileDateMap;
                });
            });
        }, Q({}));
    }