Menggunakan async / await dengan perulangan forEach
Apakah ada masalah dengan menggunakan async
/ await
dalam satu forEach
loop? Saya mencoba untuk mengulang melalui array file dan await
isi setiap file.
import fs from 'fs-promise'
async function printFiles () {
const files = await getFilePaths() // Assume this works fine
files.forEach(async (file) => {
const contents = await fs.readFile(file, 'utf8')
console.log(contents)
})
}
printFiles()
Kode ini berfungsi, tetapi apakah ada yang salah dengan ini? Saya meminta seseorang memberi tahu saya bahwa Anda tidak seharusnya menggunakan async
/ await
dalam fungsi urutan yang lebih tinggi seperti ini, jadi saya hanya ingin bertanya apakah ada masalah dengan ini.
Jawaban
Tentu kodenya berfungsi, tapi saya cukup yakin itu tidak melakukan apa yang Anda harapkan. Ini hanya mengaktifkan beberapa panggilan asinkron, tetapi printFiles
fungsinya segera kembali setelah itu.
Membaca secara berurutan
Jika Anda ingin membaca file secara berurutan, Anda tidak dapat menggunakannyaforEach
. Cukup gunakan for … of
loop modern sebagai gantinya, yang await
akan berfungsi seperti yang diharapkan:
async function printFiles () {
const files = await getFilePaths();
for (const file of files) {
const contents = await fs.readFile(file, 'utf8');
console.log(contents);
}
}
Membaca secara paralel
Jika Anda ingin membaca file secara paralel, Anda tidak dapat menggunakannyaforEach
. Setiap async
panggilan fungsi callback memang mengembalikan sebuah promise, tetapi Anda membuangnya alih-alih menunggunya. Cukup gunakan map
sebagai gantinya, dan Anda bisa menunggu berbagai janji yang akan Anda dapatkan Promise.all
:
async function printFiles () {
const files = await getFilePaths();
await Promise.all(files.map(async (file) => {
const contents = await fs.readFile(file, 'utf8')
console.log(contents)
}));
}
Dengan ES2018, Anda dapat menyederhanakan semua jawaban di atas menjadi:
async function printFiles () {
const files = await getFilePaths()
for await (const contents of fs.readFile(file, 'utf8')) {
console.log(contents)
}
}
Lihat spesifikasi: proposal-async-iteration
2018-09-10: Jawaban ini mendapatkan banyak perhatian baru-baru ini, silakan lihat postingan blog Axel Rauschmayer untuk informasi lebih lanjut tentang asynchronous iteration: ES2018: asynchronous iteration
Alih-alih Promise.all
dalam hubungannya dengan Array.prototype.map
(yang tidak menjamin urutan Promise
penyelesaian), saya menggunakan Array.prototype.reduce
, dimulai dengan diselesaikan Promise
:
async function printFiles () {
const files = await getFilePaths();
await files.reduce(async (promise, file) => {
// This line will wait for the last async function to finish.
// The first iteration uses an already resolved Promise
// so, it will immediately continue.
await promise;
const contents = await fs.readFile(file, 'utf8');
console.log(contents);
}, Promise.resolve());
}
The p-iterasi modul alat NPM metode Array iterasi sehingga mereka dapat digunakan dalam cara yang sangat sederhana dengan async / Tunggulah.
Contoh kasus Anda:
const { forEach } = require('p-iteration');
const fs = require('fs-promise');
(async function printFiles () {
const files = await getFilePaths();
await forEach(files, async (file) => {
const contents = await fs.readFile(file, 'utf8');
console.log(contents);
});
})();
Berikut beberapa forEachAsync
prototipe. Perhatikan Anda akan membutuhkannya await
:
Array.prototype.forEachAsync = async function (fn) {
for (let t of this) { await fn(t) }
}
Array.prototype.forEachAsyncParallel = async function (fn) {
await Promise.all(this.map(fn));
}
Perhatikan meskipun Anda dapat memasukkan ini ke dalam kode Anda sendiri, Anda tidak boleh menyertakan ini di perpustakaan yang Anda distribusikan kepada orang lain (untuk menghindari pencemaran global mereka).
Selain jawaban @ Bergi , saya ingin menawarkan alternatif ketiga. Ini sangat mirip dengan contoh ke-2 @ Bergi, tetapi alih-alih menunggu satu readFile
per satu , Anda membuat serangkaian janji, yang masing-masing Anda tunggu di akhir.
import fs from 'fs-promise';
async function printFiles () {
const files = await getFilePaths();
const promises = files.map((file) => fs.readFile(file, 'utf8'))
const contents = await Promise.all(promises)
contents.forEach(console.log);
}
Perhatikan bahwa fungsi yang diteruskan ke .map()
tidak perlu async
, karena tetap fs.readFile
mengembalikan objek Promise. Karenanya promises
adalah larik objek Promise, yang dapat dikirim ke Promise.all()
.
Dalam jawaban @ Bergi, konsol dapat mencatat konten file dalam urutan pembacaannya. Misalnya jika file yang sangat kecil selesai dibaca sebelum file yang sangat besar, itu akan dicatat terlebih dahulu, bahkan jika file kecil muncul setelah file besar dalam files
larik. Namun, dalam metode saya di atas, Anda dijamin konsol akan mencatat file dalam urutan yang sama seperti array yang disediakan.
Solusi Bergi bekerja dengan baik bila fs
didasarkan pada janji. Anda bisa menggunakan bluebird
, fs-extra
atau fs-promise
untuk ini.
Namun, solusi untukfs
perpustakaan asli node adalah sebagai berikut:
const result = await Promise.all(filePaths
.map( async filePath => {
const fileContents = await getAssetFromCache(filePath, async function() {
// 1. Wrap with Promise
// 2. Return the result of the Promise
return await new Promise((res, rej) => {
fs.readFile(filePath, 'utf8', function(err, data) {
if (data) {
res(data);
}
});
});
});
return fileContents;
}));
Catatan: secara
require('fs')
wajib mengambil fungsi sebagai argumen ke-3, jika tidak, akan muncul kesalahan:
TypeError [ERR_INVALID_CALLBACK]: Callback must be a function
Kedua solusi di atas berfungsi, namun, Antonio melakukan pekerjaan dengan lebih sedikit kode, berikut adalah cara membantu saya menyelesaikan data dari database saya, dari beberapa referensi anak yang berbeda dan kemudian mendorong semuanya ke dalam array dan menyelesaikannya dengan janji. selesai:
Promise.all(PacksList.map((pack)=>{
return fireBaseRef.child(pack.folderPath).once('value',(snap)=>{
snap.forEach( childSnap => {
const file = childSnap.val()
file.id = childSnap.key;
allItems.push( file )
})
})
})).then(()=>store.dispatch( actions.allMockupItems(allItems)))
Sangat mudah untuk memunculkan beberapa metode dalam file yang akan menangani data asinkron dalam urutan serial dan memberikan rasa yang lebih konvensional pada kode Anda. Sebagai contoh:
module.exports = function () {
var self = this;
this.each = async (items, fn) => {
if (items && items.length) {
await Promise.all(
items.map(async (item) => {
await fn(item);
}));
}
};
this.reduce = async (items, fn, initialValue) => {
await self.each(
items, async (item) => {
initialValue = await fn(initialValue, item);
});
return initialValue;
};
};
sekarang, dengan asumsi itu disimpan di './myAsync.js' Anda dapat melakukan sesuatu yang mirip dengan di bawah ini dalam file yang berdekatan:
...
/* your server setup here */
...
var MyAsync = require('./myAsync');
var Cat = require('./models/Cat');
var Doje = require('./models/Doje');
var example = async () => {
var myAsync = new MyAsync();
var doje = await Doje.findOne({ name: 'Doje', noises: [] }).save();
var cleanParams = [];
// FOR EACH EXAMPLE
await myAsync.each(['bork', 'concern', 'heck'],
async (elem) => {
if (elem !== 'heck') {
await doje.update({ $push: { 'noises': elem }});
}
});
var cat = await Cat.findOne({ name: 'Nyan' });
// REDUCE EXAMPLE
var friendsOfNyanCat = await myAsync.reduce(cat.friends,
async (catArray, friendId) => {
var friend = await Friend.findById(friendId);
if (friend.name !== 'Long cat') {
catArray.push(friend.name);
}
}, []);
// Assuming Long Cat was a friend of Nyan Cat...
assert(friendsOfNyanCat.length === (cat.friends.length - 1));
}
Solusi ini juga dioptimalkan untuk memori sehingga Anda dapat menjalankannya pada 10.000 item data dan permintaan. Beberapa solusi lain di sini akan merusak server pada kumpulan data yang besar.
Di TypeScript:
export async function asyncForEach<T>(array: Array<T>, callback: (item: T, index: number) => void) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index);
}
}
Cara Penggunaan?
await asyncForEach(receipts, async (eachItem) => {
await ...
})
Satu peringatan penting adalah: await + for .. of
Metode dan forEach + async
caranya sebenarnya memiliki pengaruh yang berbeda.
Memiliki await
di dalam for
loop nyata akan memastikan semua panggilan async dijalankan satu per satu. Dan forEach + async
cara tersebut akan menjalankan semua janji pada saat yang sama, yang lebih cepat tetapi terkadang kewalahan ( jika Anda melakukan kueri DB atau mengunjungi beberapa layanan web dengan batasan volume dan tidak ingin mengaktifkan 100.000 panggilan sekaligus).
Anda juga dapat menggunakan reduce + promise
(kurang elegan) jika Anda tidak menggunakan async/await
dan ingin memastikan file dibaca satu demi satu .
files.reduce((lastPromise, file) =>
lastPromise.then(() =>
fs.readFile(file, 'utf8')
), Promise.resolve()
)
Atau Anda dapat membuat forEachAsync untuk membantu tetapi pada dasarnya menggunakan yang sama untuk loop yang mendasari.
Array.prototype.forEachAsync = async function(cb){
for(let x of this){
await cb(x);
}
}
Hanya menambahkan jawaban asli
- Sintaks pembacaan paralel pada jawaban asli terkadang membingungkan dan sulit dibaca, mungkin kita dapat menuliskannya dengan pendekatan yang berbeda
async function printFiles() {
const files = await getFilePaths();
const fileReadPromises = [];
const readAndLogFile = async filePath => {
const contents = await fs.readFile(file, "utf8");
console.log(contents);
return contents;
};
files.forEach(file => {
fileReadPromises.push(readAndLogFile(file));
});
await Promise.all(fileReadPromises);
}
- Untuk operasi sekuensial, tidak hanya untuk ... of , loop for normal juga akan berfungsi
async function printFiles() {
const files = await getFilePaths();
for (let i = 0; i < files.length; i++) {
const file = files[i];
const contents = await fs.readFile(file, "utf8");
console.log(contents);
}
}
Suka tanggapan @ Bergi, tapi dengan satu perbedaan.
Promise.all
menolak semua janji jika ada yang ditolak.
Jadi, gunakan rekursi.
const readFilesQueue = async (files, index = 0) {
const contents = await fs.readFile(files[index], 'utf8')
console.log(contents)
return files.length <= index
? readFilesQueue(files, ++index)
: files
}
const printFiles async = () => {
const files = await getFilePaths();
const printContents = await readFilesQueue(files)
return printContents
}
printFiles()
PS
readFilesQueue
di luar printFiles
sebab akibat efek samping * yang diperkenalkan oleh console.log
, lebih baik mengejek, menguji, dan atau memata-matai jadi, tidak keren memiliki fungsi yang mengembalikan konten (sidenote).
Oleh karena itu, kode hanya dapat dirancang dengan: tiga fungsi terpisah yang "murni" ** dan tidak menimbulkan efek samping, memproses seluruh daftar dan dapat dengan mudah dimodifikasi untuk menangani kasus yang gagal.
const files = await getFilesPath()
const printFile = async (file) => {
const content = await fs.readFile(file, 'utf8')
console.log(content)
}
const readFiles = async = (files, index = 0) => {
await printFile(files[index])
return files.lengh <= index
? readFiles(files, ++index)
: files
}
readFiles(files)
Pengeditan masa depan / status saat ini
Node mendukung menunggu tingkat atas (ini belum memiliki plugin, tidak akan memiliki dan dapat diaktifkan melalui bendera harmoni), ini keren tetapi tidak menyelesaikan satu masalah (secara strategis saya hanya bekerja pada versi LTS). Bagaimana cara mendapatkan file?
Menggunakan komposisi. Diberikan kode, menyebabkan saya sensasi bahwa ini ada di dalam modul, jadi, harus memiliki fungsi untuk melakukannya. Jika tidak, Anda harus menggunakan IIFE untuk menggabungkan kode peran ke dalam fungsi asinkron yang membuat modul sederhana yang melakukan semuanya untuk Anda, atau Anda dapat menggunakan komposisi yang benar.
// more complex version with IIFE to a single module
(async (files) => readFiles(await files())(getFilesPath)
Perhatikan bahwa nama variabel berubah karena semantik. Anda mengirimkan functor (fungsi yang dapat dipanggil oleh fungsi lain) dan menerima penunjuk pada memori yang berisi blok awal logika aplikasi.
Tapi, apakah itu bukan modul dan Anda perlu mengekspor logikanya?
Gabungkan fungsi dalam fungsi asinkron.
export const readFilesQueue = async () => {
// ... to code goes here
}
Atau ubah nama variabel, apapun ...
*
oleh efek samping menans setiap efek bakteri dari aplikasi yang dapat mengubah status / perilaku atau memperkenalkan bug dalam aplikasi, seperti IO.
**
dengan "murni", itu dalam apostrof karena fungsinya tidak murni dan kode dapat disatukan ke versi murni, ketika tidak ada output konsol, hanya manipulasi data.
Selain itu, untuk menjadi murni, Anda harus bekerja dengan monad yang menangani efek samping, yang rawan kesalahan, dan memperlakukan kesalahan itu secara terpisah dari aplikasi.
Menggunakan Task, futurize, dan List yang dapat dijelajahi, Anda dapat melakukannya
async function printFiles() {
const files = await getFiles();
List(files).traverse( Task.of, f => readFile( f, 'utf-8'))
.fork( console.error, console.log)
}
Berikut adalah cara Anda menyiapkannya
import fs from 'fs';
import { futurize } from 'futurize';
import Task from 'data.task';
import { List } from 'immutable-ext';
const future = futurizeP(Task)
const readFile = future(fs.readFile)
Cara lain untuk menyusun kode yang diinginkan adalah
const printFiles = files =>
List(files).traverse( Task.of, fn => readFile( fn, 'utf-8'))
.fork( console.error, console.log)
Atau mungkin lebih berorientasi fungsional
// 90% of encodings are utf-8, making that use case super easy is prudent
// handy-library.js
export const readFile = f =>
future(fs.readFile)( f, 'utf-8' )
export const arrayToTaskList = list => taskFn =>
List(files).traverse( Task.of, taskFn )
export const readFiles = files =>
arrayToTaskList( files, readFile )
export const printFiles = files =>
readFiles(files).fork( console.error, console.log)
Kemudian dari fungsi induk
async function main() {
/* awesome code with side-effects before */
printFiles( await getFiles() );
/* awesome code with side-effects after */
}
Jika Anda benar-benar menginginkan lebih banyak fleksibilitas dalam pengkodean, Anda bisa melakukan ini (untuk bersenang-senang, saya menggunakan operator Pipe Forward yang diusulkan )
import { curry, flip } from 'ramda'
export const readFile = fs.readFile
|> future,
|> curry,
|> flip
export const readFileUtf8 = readFile('utf-8')
PS - Saya tidak mencoba kode ini di konsol, mungkin ada beberapa kesalahan ketik ... "gaya bebas lurus, dari atas kubah!" seperti yang dikatakan anak-anak 90-an. :-p
Saat ini properti prototipe Array.forEach tidak mendukung operasi asinkron, tetapi kita dapat membuat poly-fill kita sendiri untuk memenuhi kebutuhan kita.
// Example of asyncForEach Array poly-fill for NodeJs
// file: asyncForEach.js
// Define asynForEach function
async function asyncForEach(iteratorFunction){
let indexer = 0
for(let data of this){
await iteratorFunction(data, indexer)
indexer++
}
}
// Append it as an Array prototype property
Array.prototype.asyncForEach = asyncForEach
module.exports = {Array}
Dan itu dia! Anda sekarang memiliki metode forEach asinkron yang tersedia pada larik apa pun yang ditentukan setelah ini ke operasi.
Mari kita uji ...
// Nodejs style
// file: someOtherFile.js
const readline = require('readline')
Array = require('./asyncForEach').Array
const log = console.log
// Create a stream interface
function createReader(options={prompt: '>'}){
return readline.createInterface({
input: process.stdin
,output: process.stdout
,prompt: options.prompt !== undefined ? options.prompt : '>'
})
}
// Create a cli stream reader
async function getUserIn(question, options={prompt:'>'}){
log(question)
let reader = createReader(options)
return new Promise((res)=>{
reader.on('line', (answer)=>{
process.stdout.cursorTo(0, 0)
process.stdout.clearScreenDown()
reader.close()
res(answer)
})
})
}
let questions = [
`What's your name`
,`What's your favorite programming language`
,`What's your favorite async function`
]
let responses = {}
async function getResponses(){
// Notice we have to prepend await before calling the async Array function
// in order for it to function as expected
await questions.asyncForEach(async function(question, index){
let answer = await getUserIn(question)
responses[question] = answer
})
}
async function main(){
await getResponses()
log(responses)
}
main()
// Should prompt user for an answer to each question and then
// log each question and answer as an object to the terminal
Kita bisa melakukan hal yang sama untuk beberapa fungsi array lainnya seperti map ...
async function asyncMap(iteratorFunction){
let newMap = []
let indexer = 0
for(let data of this){
newMap[indexer] = await iteratorFunction(data, indexer, this)
indexer++
}
return newMap
}
Array.prototype.asyncMap = asyncMap
... dan seterusnya :)
Beberapa hal yang perlu diperhatikan:
- IteratorFunction Anda harus berupa fungsi atau janji async
- Larik apa pun yang dibuat sebelumnya
Array.prototype.<yourAsyncFunc> = <yourAsyncFunc>
tidak akan memiliki fitur ini
Hari ini saya menemukan banyak solusi untuk ini. Menjalankan fungsi async await di forEach Loop. Dengan membangun pembungkus di sekitar kita dapat mewujudkannya.
Berbagai cara yang melaluinya dapat dilakukan dan itu adalah sebagai berikut,
Metode 1: Menggunakan pembungkus.
await (()=>{
return new Promise((resolve,reject)=>{
items.forEach(async (item,index)=>{
try{
await someAPICall();
} catch(e) {
console.log(e)
}
count++;
if(index === items.length-1){
resolve('Done')
}
});
});
})();
Metode 2: Menggunakan yang sama sebagai fungsi umum Array.prototype
Array.prototype.forEachAsync.js
if(!Array.prototype.forEachAsync) {
Array.prototype.forEachAsync = function (fn){
return new Promise((resolve,reject)=>{
this.forEach(async(item,index,array)=>{
await fn(item,index,array);
if(index === array.length-1){
resolve('done');
}
})
});
};
}
Penggunaan:
require('./Array.prototype.forEachAsync');
let count = 0;
let hello = async (items) => {
// Method 1 - Using the Array.prototype.forEach
await items.forEachAsync(async () => {
try{
await someAPICall();
} catch(e) {
console.log(e)
}
count++;
});
console.log("count = " + count);
}
someAPICall = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("done") // or reject('error')
}, 100);
})
}
hello(['', '', '', '']); // hello([]) empty array is also be handled by default
Metode 3:
Menggunakan Promise.all
await Promise.all(items.map(async (item) => {
await someAPICall();
count++;
}));
console.log("count = " + count);
Metode 4: Tradisional for loop atau modern for loop
// Method 4 - using for loop directly
// 1. Using the modern for(.. in..) loop
for(item in items){
await someAPICall();
count++;
}
//2. Using the traditional for loop
for(let i=0;i<items.length;i++){
await someAPICall();
count++;
}
console.log("count = " + count);
Anda dapat menggunakan Array.prototype.forEach
, tetapi async / await tidak begitu kompatibel. Hal ini karena promise yang ditampilkan dari callback asinkron diharapkan akan diselesaikan, tetapi Array.prototype.forEach
tidak menyelesaikan promise apa pun dari eksekusi callbacknya. Jadi, Anda dapat menggunakan forEach, tetapi Anda harus menangani sendiri resolusi promise tersebut.
Berikut ini cara membaca dan mencetak setiap file secara seri menggunakan Array.prototype.forEach
async function printFilesInSeries () {
const files = await getFilePaths()
let promiseChain = Promise.resolve()
files.forEach((file) => {
promiseChain = promiseChain.then(() => {
fs.readFile(file, 'utf8').then((contents) => {
console.log(contents)
})
})
})
await promiseChain
}
Berikut adalah cara (tetap menggunakan Array.prototype.forEach
) untuk mencetak isi file secara paralel
async function printFilesInParallel () {
const files = await getFilePaths()
const promises = []
files.forEach((file) => {
promises.push(
fs.readFile(file, 'utf8').then((contents) => {
console.log(contents)
})
)
})
await Promise.all(promises)
}
Untuk melihat bagaimana itu bisa salah, cetak console.log di akhir metode.
Hal-hal yang bisa salah secara umum:
- Pesanan sewenang-wenang.
- printFiles dapat selesai dijalankan sebelum mencetak file.
- Pertunjukkan yang buruk.
Ini tidak selalu salah tetapi sering kali dalam kasus penggunaan standar.
Umumnya, menggunakan forEach akan menghasilkan semua kecuali yang terakhir. Ini akan memanggil setiap fungsi tanpa menunggu fungsi yang berarti ia memberitahu semua fungsi untuk memulai kemudian selesai tanpa menunggu fungsi selesai.
import fs from 'fs-promise'
async function printFiles () {
const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'))
for(const file of files)
console.log(await file)
}
printFiles()
Ini adalah contoh dalam JS asli yang akan mempertahankan urutan, mencegah fungsi kembali sebelum waktunya, dan secara teori mempertahankan kinerja yang optimal.
Ini akan:
- Memulai semua pembacaan file terjadi secara paralel.
- Pertahankan pesanan melalui penggunaan peta untuk memetakan nama file yang akan ditunggu.
- Tunggu setiap janji dalam urutan yang ditentukan oleh array.
Dengan solusi ini, file pertama akan ditampilkan segera setelah tersedia tanpa harus menunggu yang lain tersedia terlebih dahulu.
Ini juga akan memuat semua file pada saat yang sama daripada harus menunggu yang pertama selesai sebelum pembacaan file kedua dapat dimulai.
Satu-satunya kekurangan ini dan versi aslinya adalah jika beberapa pembacaan dimulai sekaligus maka lebih sulit untuk menangani kesalahan karena memiliki lebih banyak kesalahan yang dapat terjadi pada satu waktu.
Dengan versi yang membaca file pada suatu waktu maka akan berhenti pada kegagalan tanpa membuang waktu mencoba membaca file lagi. Bahkan dengan sistem pembatalan yang rumit, mungkin sulit untuk menghindari kegagalan pada file pertama tetapi membaca sebagian besar file lainnya juga.
Performa tidak selalu bisa diprediksi. Sementara banyak sistem akan lebih cepat dengan file paralel membaca beberapa akan lebih memilih berurutan. Beberapa bersifat dinamis dan mungkin bergeser saat dimuat, pengoptimalan yang menawarkan latensi tidak selalu menghasilkan throughput yang baik dalam perselisihan yang berat.
Juga tidak ada penanganan kesalahan dalam contoh itu. Jika sesuatu mengharuskan mereka untuk berhasil ditampilkan atau tidak ditampilkan sama sekali, itu tidak akan berhasil.
Eksperimen mendalam direkomendasikan dengan console.log di setiap tahap dan solusi pembacaan file palsu (sebagai gantinya penundaan acak). Meskipun banyak solusi tampaknya melakukan hal yang sama dalam kasus sederhana, semuanya memiliki perbedaan halus yang membutuhkan pengawasan ekstra untuk diperas.
Gunakan tiruan ini untuk membantu membedakan antara solusi:
(async () => {
const start = +new Date();
const mock = () => {
return {
fs: {readFile: file => new Promise((resolve, reject) => {
// Instead of this just make three files and try each timing arrangement.
// IE, all same, [100, 200, 300], [300, 200, 100], [100, 300, 200], etc.
const time = Math.round(100 + Math.random() * 4900);
console.log(`Read of ${file} started at ${new Date() - start} and will take ${time}ms.`)
setTimeout(() => {
// Bonus material here if random reject instead.
console.log(`Read of ${file} finished, resolving promise at ${new Date() - start}.`);
resolve(file);
}, time);
})},
console: {log: file => console.log(`Console Log of ${file} finished at ${new Date() - start}.`)},
getFilePaths: () => ['A', 'B', 'C', 'D', 'E']
};
};
const printFiles = (({fs, console, getFilePaths}) => {
return async function() {
const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'));
for(const file of files)
console.log(await file);
};
})(mock());
console.log(`Running at ${new Date() - start}`);
await printFiles();
console.log(`Finished running at ${new Date() - start}`);
})();
Mirip dengan Antonio Val p-iteration
, modul npm alternatif adalah async-af
:
const AsyncAF = require('async-af');
const fs = require('fs-promise');
function printFiles() {
// since AsyncAF accepts promises or non-promises, there's no need to await here
const files = getFilePaths();
AsyncAF(files).forEach(async file => {
const contents = await fs.readFile(file, 'utf8');
console.log(contents);
});
}
printFiles();
Atau, async-af
memiliki metode statis (log / logAF) yang mencatat hasil janji:
const AsyncAF = require('async-af');
const fs = require('fs-promise');
function printFiles() {
const files = getFilePaths();
AsyncAF(files).forEach(file => {
AsyncAF.log(fs.readFile(file, 'utf8'));
});
}
printFiles();
Namun, keuntungan utama dari library ini adalah Anda dapat menghubungkan metode asinkron untuk melakukan sesuatu seperti:
const aaf = require('async-af');
const fs = require('fs-promise');
const printFiles = () => aaf(getFilePaths())
.map(file => fs.readFile(file, 'utf8'))
.forEach(file => aaf.log(file));
printFiles();