Javascript 承诺链接 - 奇怪的行为
Javascript promises chaining - strange behavior
我正在使用此代码进行测试:
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);
});
我运行将其与节点 v 6.9.1 结合使用,结果是:
.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
到目前为止,还不错。但有时,我得到了 10 个中的 1 个 运行:
.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
请注意有时在实际循环结束之前执行最终结果。为什么?我无法自己解决这个问题,我需要帮助来了解导致此错误的原因。
P.S。位于底部的文件始终不是 functions-4.js。
请帮忙
如果您只想在文件的所有计算完成后才解析,您可能应该在函数 calculateSize(files)
中使用 Promise#all
。
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
})
})
}
您甚至可以通过删除最终的 then
回调,使函数将文件数组映射到大小数组。
我认为您的第二个 then
没有在等待 calculateSize()。
试试这个
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); }
);
我建议不要推出自己的 promisification,这很乏味且容易出错。让像 bluebird 这样的图书馆为您做这件事。
连同 bluebird 提供的其他功能,例如 .map()
和 .reduce()
的实现,您的代码可以像这样简单直接:
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));
我正在使用此代码进行测试:
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);
});
我运行将其与节点 v 6.9.1 结合使用,结果是:
.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
到目前为止,还不错。但有时,我得到了 10 个中的 1 个 运行:
.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
请注意有时在实际循环结束之前执行最终结果。为什么?我无法自己解决这个问题,我需要帮助来了解导致此错误的原因。
P.S。位于底部的文件始终不是 functions-4.js。
请帮忙
如果您只想在文件的所有计算完成后才解析,您可能应该在函数 calculateSize(files)
中使用 Promise#all
。
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
})
})
}
您甚至可以通过删除最终的 then
回调,使函数将文件数组映射到大小数组。
我认为您的第二个 then
没有在等待 calculateSize()。
试试这个
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); }
);
我建议不要推出自己的 promisification,这很乏味且容易出错。让像 bluebird 这样的图书馆为您做这件事。
连同 bluebird 提供的其他功能,例如 .map()
和 .reduce()
的实现,您的代码可以像这样简单直接:
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));