以下代码负责读取文件。我的要求是如何查找是否已读取所有文件,以便我可以从父函数返回或解析promise(readmultifiles)。
$.when(readmultifiles(files))
.then(function(){//all files uploaded}))
上面的代码启动文件读取。在阅读所有文件时可以做些什么 回调已完成或可以返回。
function readmultifiles(files) {
// Read first file
setup_reader(files, 0);
}
function setup_reader(files, i) {
var file = files[i];
var name = file.name;
var reader = new FileReader();
reader.onload = function(e) {
readerLoaded(e, files, i, name);
};
reader.readAsBinaryString(file);
// After reading, read the next file.
}
function readerLoaded(e, files, i, name) {
// get file content
var bin = e.target.result;
// do sth with text
// If there's a file left to load
if (i < files.length - 1) {
// Load the next file
setup_reader(files, i + 1);
}
}
答案 0 :(得分:5)
在使用您的实现可以学习的承诺的好设计中,有几件事需要考虑:
readFile()
。它还使readFile()
在您的项目或未来项目的其他地方更有用。鉴于这一切,这里有五种方法来实现你的代码 - 使用标准的promises,使用jQuery promises和你的操作序列,或者并行运行并使用Bluebird的承诺。在所有情况下,您最终都会得到一系列结果。
使用标准承诺宣传readFile()
首先,让我们&#34;宣传&#34;您的readFile操作,以便您可以使用promise逻辑来控制事物。
function readFile(file) {
return new Promise(function(resolve, reject) {
var reader = new FileReader();
reader.onload = function(e) {
resolve(e.target.result);
};
reader.onerror = reader.onabort = reject;
reader.readAsBinaryString(file);
});
}
使用标准承诺,并行执行所有操作
要并行运行所有文件操作并按顺序返回所有结果并使用标准承诺,您可以这样做:
function readmultifiles(files) {
return Promise.all(files.map(readFile));
}
// sample usage
readmultifiles(arrayOfFiles).then(function(results) {
// all results in the results array here
});
使用标准承诺,按顺序执行所有操作
按顺序运行所有文件操作(这看起来不像你需要在这里执行,因为所有操作都是独立的,即使你的原始代码对它们进行排序)并按顺序返回所有结果并使用标准的promises,你可以这样做。
这种有点标准的排序设计模式使用.reduce()
对数组进行排序并将所有操作链接在一起,这样它们就可以在链的序列中一次运行一个:
function readmultifiles(files) {
var results = [];
files.reduce(function(p, file) {
return p.then(function() {
return readFile(file).then(function(data) {
// put this result into the results array
results.push(data);
});
});
}, Promise.resolve()).then(function() {
// make final resolved value be the results array
return results;
});
}
// sample usage
readmultifiles(arrayOfFiles).then(function(results) {
// all results in the results array here
});
并且,以下是使用jQuery promises看起来的样子
使用jQuery承诺宣传readFile()
:
function readFile(file) {
return new $.Deferred(function(def) {
var reader = new FileReader();
reader.onload = function() {
def.resolve(e.target.result);
};
reader.onerror = reader.onabort = def.reject;
reader.readAsBinaryString(file);
}).promise();
}
与jQuery并行运行:
function readmultifiles(files) {
return $.when.apply($, files.map(readFile));
}
// sample usage
readmultifiles(arrayOfFiles).then(function() {
var results = Array.prototype.slice(arguments);
// all results in the results array here
});
并依次使用jQuery
运行function readmultifiles(files) {
var results = [];
files.reduce(function(p, file) {
return p.then(function() {
return readFile(file).then(function(data) {
// put this result into the results array
results.push(data);
});
});
}, $.Deferred().resolve()).then(function() {
// make final resolved value be the results array
return results;
});
}
// sample usage
readmultifiles(arrayOfFiles).then(function(results) {
// all results in the results array here
});
蓝鸟实施
而且,为了完整起见,我将使用一个具有其他功能的more advanced promise library like Bluebird来展示它的外观。并行代码和readFile()
的实现与标准promise相同,但对于顺序实现,它可以利用一些内置的Bluebird操作来对异步操作进行排序,它只包括:
function readmultifiles(files) {
return Promise.mapSeries(files, readFile);
}
// sample usage
readmultifiles(arrayOfFiles).then(function(results) {
// all results in the results array here
});
答案 1 :(得分:0)
如果我将代码结构更改为此
,该怎么办?
$.when(readmultifiles(files)).then(
function(status) {
alert(status + ", things are going well");
},
function(status) {
alert(status + ", you fail this time");
},
function(status) {
$("body").append(status);
}
);
function readmultifiles(files) {
var dfrd = $.Deferred();
// Read first file
setup_reader(files, 0);
function setup_reader(files, i) {
var file = files[i];
var name = file.name;
var reader = new FileReader();
reader.onload = function(e) {
readerLoaded(e, files, i, name);
};
reader.readAsBinaryString(file);
// After reading, read the next file.
}
function readerLoaded(e, files, i, name) {
// get file content
var bin = e.target.result;
// do sth with text
namee.push(name);
// If there's a file left to load
if (i < files.length - 1) {
// Load the next file
setup_reader(files, i + 1);
} else {
dfrd.resolve(namee.join(','));
}
}
return dfrd.promise();
}