简体   繁体   中英

Javascript promises chaining - strange behavior

I am testing with this code:

var http = require('http');
var fs = require('fs');

function getFullPath(file){
    return new Promise(function(resolve, reject){
        fs.realpath(file, function(err, path){
            resolve(path);
        });
    });
}

function getFileSize(file){
    return new Promise(function(resolve, reject){
        fs.stat(file, function(err, stats){
            resolve(stats.size);
        });
    });
}

function calculateSize(files){
    var size = 0;
    var files_count = files.length-1;

    return new Promise(function(resolve, reject){
        files.forEach(function(file, i){
            getFullPath(file).then(getFileSize).then(function(tempSize){
                size += tempSize;
                console.log(file, tempSize);
                if(files_count == i){
                    resolve(size);
                }
            });
        });
    });
}

function getFiles(path){

    console.warn('Staring path:',path);

    return new Promise(function(resolve, reject){
        fs.readdir(path, function(err, files){

            if(err || !files){
                reject(err);
            } else {
                resolve(files);
            }
        });
    });
}

getFiles('/home/galio/DEV/js-sandbox').then(function(result){
    return calculateSize(result);
}, function(err){
    console.log('ERROR:', err);
}).then(function(size){
    console.log('All files size is: ', size);
});

I am running it with node v 6.9.1 , result of it is:

.eslintrc.json 528
.git 4096
.gitignore 26
README 0
callbacks.js 1402
functions-1.js 530
functions-2.js 564
functions-3.js 1798
functions-4.js 737
functions-5.js 1045
All files size is:  10726

So far, so good. BUT sometimes , maybe 1 of 10 run i got:

.eslintrc.json 528
.git 4096
.gitignore 26
README 0
functions-1.js 530
callbacks.js 1402
functions-2.js 564
functions-3.js 1798
functions-5.js 1045
All files size is:  9989
functions-4.js 737

Notice how sometimes the final result is executed before the actual loop finishes. Why? I cant resolve this myself and i need help to realize what makes this error.

PS The file that going at the bottom is not functions-4.js always.

Pls, help

You should probably be using Promise#all in your function calculateSize(files) if you want to resolve only when all of the calculations for the files are finished.

function calculateSize(files) {
    return Promise.all(files.map(function (file) {
        return getFullPath(file).then(getFileSize).then(function(size) {
                console.log(file, size)
                return size
            })
        })
    }).then(function (sizes) {
        return sizes.reduce(function (a, b) {
            return a + b
        })
    })
}

You could even make the function map an array of files to an array of sizes by removing the final then callback.

I would recommend against rolling your own promisification, this is tedious and error-prone. Let a library like bluebird do this for you.

Together with the other features bluebird offers, like implementations of .map() and .reduce() , your code can be made as simple and straight-forward as this:

var Promise = require('bluebird');
var path = require('path');
var fs = Promise.promisifyAll(require('fs'));

function calculateSizeAsync(dir) {
    return fs.readdirAsync(dir)
        .map(file => path.join(dir, file))
        .map(filepath => fs.statAsync(filepath))
        .reduce((total, stats) => {return total + stats.size}, 0);
}

calculateSizeAsync('/home/galio/DEV/js-sandbox')
    .then(totalSize => console.log('All files size is: ' + totalSize))
    .catch(err => console.error('ERROR:', err));

I think your second then isn't waiting for calculateSize().

Try this

getFiles('/home/galio/DEV/js-sandbox').then(function(result){
  calculateSize(result).then(function(size){
    console.log('All files size is: ', size);
  }
}, 
function(err){ console.log('ERROR:', err); }
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM