Есть несколько вещей, чтобы рассмотреть в хорошем дизайне с использованием обещаний, что ваша реализация может поучиться:
- Создать обещание (называемое «обещание») с самого низкого уровня a синхронизация у вас есть. Затем вы можете использовать функции обещания для управления логическим потоком и распространения ошибок, и ваш код будет последовательно реализовываться с обещаниями. В этом случае это означает, что вы должны обещать
readFile()
. Он также делает readFile()
более полезным в другом месте вашего проекта или в будущих проектах.
- Убедитесь, что вы всегда правильно распространяете ошибки. С асинхронным кодом, когда вы не используете обещания, может быть трудно правильно получить ошибки обратно к исходному вызывающему, особенно если асинхронная логика заканчивается сложной (с вложенными или последовательностными операциями).
- Подумайте, должны ли быть выполнены ваши асинхронные операции или они могут выполняться параллельно. Если одна операция не зависит от другой, и вы вряд ли перегружаете какую-либо услугу несколькими запросами, то запуск параллельных операций часто приведет к более быстрому результату.
- Возвращает обещания от асинхронных функций, поэтому вызывающие могут знать, когда все будет сделано, и получить доступ к результатам async.
- Не создавайте другое обещание вокруг существующего обещания без необходимости (считается одним из обещающих анти-шаблонов).
- Если вы используете jQuery-обещания, попробуйте использовать функции jQuery, совместимые со стандартом обещаний, чтобы вы не сталкивались с проблемами совместимости в будущем или путали будущих читателей вашего кода, которые с большей вероятностью будут знать, как работают стандартные обещания.
Учитывая все это, вот пять способов реализовать ваш код, используя стандартные обещания, используя обещания jQuery, а также с вашими последовательностями операций или запускаться параллельно и используя обещания Bluebird. Во всех случаях в конце вы получаете массив результатов в порядке.
Promisify readFile()
используя стандартные обещания
Во-первых, давайте «promisify» ваша операция ReadFile, так что вы можете использовать обещание логики контролировать вещи.
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
});
Со стандартными обещаниями, все операции в последовательности
Чтобы выполнить все операции с файлами в последовательности (что не похоже на то, что вам нужно сделать здесь, потому что все операции являются независимыми, даже если ваш исходный код их упорядочивал) и возвращать все результаты в порядке и использовать стандартные обещания, вы можете сделай это.
Это несколько стандартный шаблон дизайна для секвенирования использует .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 обещает
Promisify readFile()
с помощью JQuery обещает:
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();
}
Run в параллель с 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
});
Bluebird реализация
И, для полноты картины, я 'Покажу вам, как это выглядит, используя немного more advanced promise library like Bluebird tha t имеет дополнительные возможности, которые здесь полезны. Параллельный код и реализация readFile()
такие же, как для стандартных обещаний, но для последовательного осуществления, он может воспользоваться некоторыми встроенными Bluebird операций для работы последовательности асинхронной, и было бы просто состоять из:
function readmultifiles(files) {
return Promise.mapSeries(files, readFile);
}
// sample usage
readmultifiles(arrayOfFiles).then(function(results) {
// all results in the results array here
});
Прочитайте [этот ответ о '$ .when()'] (http://stackoverflow.com/questions/25613624/q-promise-difference-between-when-and-then/25614136#25614136) и этот [Пробовал ' $ .when() 'и не повезло] (http://stackoverflow.com/questions/24549066/tried-when-and-then-no-lucky/24549220#24549220). Вы должны передать ему ряд обещаний, которые разрешаются, когда их основные операции асинхронного копирования завершаются. У него нет волшебных сил, чтобы делать все это самостоятельно. Все это контролирует группу обещаний. Если вы хотите его использовать, вы можете начать с того, что ваши операции async используют и разрешают обещания. – jfriend00
Привет jFriend, Можете ли вы проверить мой ответ. –