Мне нравится использовать функции, возвращающие async-обещания, например:
// async style
await copyDirectory(`~/myfiles`,`~/copy-of-myfiles`)
// or even old-skool
copyDirectory(`~/myfiles`,`~/copy-of-my-files`)
.then(console.log)
.catch(console.error);
Однако иногда при выполнении асинхронных операций я хочу отслеживать прогресс (или вводить некоторые крючки жизненного цикла), например:
- использовать
beforeFileCopyкрючок для логирования имени скопированного файла - использовать
afterFileCopyподключите к логу имя скопированного файла (или сделайте что-нибудь более осмысленное)
Каков наиболее идиоматичный (элегантный / читаемый / принятый сообществом) способ выполнения такой операции. Я пробовал что-то вроде этого:
// example-1.js
// This works and does the job, but feels very clumsy.
await copyDirectory({
fromDir: `~/myfiles`,
toDir: `~/copy-of-my-files`,
beforeFileCopy: ev=>{
console.log(`Copying file ${ev.filename}`);
},
afterFileCopy: ev=>{
console.log(`Finished file ${ev.filename}`);
}
})
// example-2.js
// Even if I use named functions for lifecycle hooks,
// it still looks clumsy to me (as those functions kind of look out out of place
await copyDirectory({
fromDir: `~/myfiles`,
toDir: `~/copy-of-my-files`,
beforeFileCopy,
afterFileCopy,
})
function beforeFileCopy(ev){
console.log(`Copying file ${ev.filename}`);
}
function afterFileCopy(ev){
console.log(`Finished file ${ev.filename}`);
}
Я также пытался сделать это с помощью шаблона {Event Emitter} (в основном избавляясь от Promises и просто используя эмиттер событий), и хотя он выглядит субъективно более «идиоматичным», без обещаний неудобно использовать его с async / await ( поскольку большая часть кода, с которым я работаю каждый день, является асинхронной функцией)
// This code follows EventEmitter pattern, but
// now it is not following async/await paradigm..
copyDirectory({
fromDir: `~/myfiles`,
toDir: `~/copy-of-my-files`,
})
.on('before-file-copy', ev=>console.log(`Copying file ${ev.filename}`))
.on('after-file-copy', ev=>console.log(`Finished file ${ev.filename}`))
.on('finished', ()=>console.log(`Finished copying directory`))
.on('error', console.error);
Конечно, я могу попытаться обернуть шаблон EventEmitter в функцию, возвращающую обещание.
// Event Emitter wrapped into Promise-function
function copyDirectoryAsync(opts){
return new Promise((resolve,reject)=>{
copyDirectory({
fromDir: `~/myfiles`,
toDir: `~/copy-of-my-files`,
})
.on('before-file-copy', ev=>console.log(`Copying file ${ev.filename}`))
.on('after-file-copy', ev=>console.log(`Finished file ${ev.filename}`))
.on('finished', resolve)
.on('error', reject);
});
}
// Whilst I did manage to wrap EventEmitter into Promise-paradigm
// I am back to square one, where If I want to expose any lifecycle
// hooks, I have to add them as parameters
await copyDirectoryAsync({
fromDir: `~/myfiles`,
toDir: `~/copy-of-my-files`,
})
// so if I want to expose lifecycle hooks from the EventEmitter
// i need to expose functions beforeXX afterXX as options
// and I get to square one where I started
await copyDirectoryAsync({
fromDir: `~/myfiles`,
toDir: `~/copy-of-my-files`,
beforeFileCopy: ()=> .... ,
afterFileCopy: ()=> .... ,
})
// and reminder that this is where I started
await copyDirectory({
fromDir: `~/myfiles`,
toDir: `~/copy-of-my-files`,
beforeFileCopy,
afterFileCopy,
})
Итак, что было бы идиоматическим (элегантным / рекомендованным сообществом / чистым) способом написания кода, который обеспечивает прогресс / жизненный цикл асинхронной операции?
1 ответ
Создавайте интерфейсы так, чтобы их было легко использовать, а не просто реализовать.
Если вам проще использовать вариант async, то нет необходимости реализовывать его с эмиттером событий и оборачивать его с помощью функции async.
Если проще использовать события, реализуйте это.
Если проще использовать асинхронный вариант, но реализация на основе событий уже существует, тогда обязательно создайте оболочку, но я не думаю, что это ваш случай.
В любом случае, думали ли вы, что требуемые аргументы фактически разделяют параметры функции?
async function copyDirectory(source, target, hooks = {})
