以下是我所拥有的:
function nextAvailableFilename(path) {
return new Promise(function (resolve, reject) {
FileSystem.exists(path, function (exists) {
if (!exists) return resolve(path);
var ext = Path.extname(path);
var pathWithoutExt = path.slice(0, -ext.length);
var match = /\d+$/.exec(pathWithoutExt);
var number = 1;
if (match) {
number = parseInt(match[0]);
pathWithoutExt = pathWithoutExt.slice(0, -match[0].length);
}
++number;
nextAvailableFilename(pathWithoutExt + number + ext).then(function () {
return resolve.apply(undefined, arguments);
}, function () {
return reject.apply(undefined, arguments);
});
});
});
}
但我最后不喜欢那个街区 - 是不是有办法替换'当前承诺与堆栈中的下一个承诺而不是让一个承诺解决下一个承诺,就像我在这里完成的那样?
答案 0 :(得分:1)
这是一个使用保证链和文件创建的版本,以避免竞争条件。我使用了bluebird promise库,所以我可以使用fs
库中的promises来简化代码和错误处理:
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
var path = require('path');
// Creates next available xxx/yyy/foo4.txt numeric sequenced file that does
// not yet exist. Returns the new filename in the promise
// Calling this function will create a new empty file.
function nextAvailableFilename(filename) {
return fs.openAsync(filename, "wx+").then(function(fd) {
return fs.closeAsync(fd).then(function() {
return filename;
});
}, function(err) {
if (err.code !== 'EEXIST') {
// unexpected file system error
// to avoid possible looping forever, we must bail
// and cause rejected promise to be returned
throw err;
}
// Previous file exists so reate a new filename
// xxx/yyy/foo4.txt becomes xxx/yyy/foo5.txt
var ext = path.extname(filename);
var filenameWithoutExt = filename.slice(0, -ext.length);
var number = 0;
var match = filenameWithoutExt.match(/\d+$/);
if (match) {
number = parseInt(match[0], 10);
filenameWithoutExt = filenameWithoutExt.slice(0, -match[0].length);
}
++number;
// call this function again, returning the promise
// which will cause it to chain onto previous promise
return nextAvailableFilename(filenameWithoutExt + number + ext);
});
}
答案 1 :(得分:0)
我想出了一个不依赖于bluebird.promisify的解决方案。 应该处理文件创建失败的情况,原因是它已经存在。
function createFile(path) {
return new Promise(function (resolve, reject) {
FileSystem.open(path, 'wx', function (err, fd) {
if (err) return reject(err);
FileSystem.close(fd, function (err) {
if (err) return reject(err);
return resolve();
});
});
});
}
// todo: make more efficient by multiplying numbers by 2 or something like http://stackoverflow.com/a/1078898/65387
function nextFile(path) {
return createFile(path).then(function () {
return path;
}, function (err) {
if (err.code !== 'EEXIST') throw err; // error other than "file exists"
var ext = Path.extname(path);
var pathWithoutExt = path.slice(0, -ext.length);
var match = /\d+$/.exec(pathWithoutExt);
var number = 2;
if (match) {
number = parseInt(match[0]) + 1;
pathWithoutExt = pathWithoutExt.slice(0, -match[0].length);
}
return nextFile(pathWithoutExt + number + ext);
});
}