There is an async iterable
class Fasta { //read file line by line and yield a class based on every four lines constructor(path) { this.path = path const filestream = fs.createReadStream(this.path) if (this.path.match(/(.fastq)|(.fq)$/)) { this.filetype = 'fastq' this.handle = readline.createInterface({ input: filestream, crlfDelay: Infinity }) } else if (this.path.match(/.gz$/)) { this.filetype = 'fqgz' this.handle = readline.createInterface({ input: filestream.pipe(zlib.createGunzip()), crlfDelay: Infinity }) } } async * [Symbol.asyncIterator]() { let counter = 0 const rec = {0: '', 1: '', 2: '', 3: ''} for await (const line of this.handle) { if (counter < 3) { rec[counter] = line.trim() counter +=1 } else if (counter == 3) { rec[counter] = line.trim() counter = 0 yield new Dna(rec[0], rec[1], rec[3]) } } } }
and I want to do someting like this.
for await (const i of zip(new Fasta(args.filea), new Fasta(args.fileb))) { // do the work }
I’ve found several walkarouds here, but they all seem to be based on Array.map(). In this way I need to create an array to carry all the data. When the files are big, things go wrong.
I tried
async function * zip(fasta1, fasta2) { for await (const [i,j] of [fasta1, fasta2]) { yield [i,j] } }
but it gave me a ‘TypeError: .for is not iterable’.
Any help would be appreciated!
Advertisement
Answer
Here’s an async variation of my answer here:
async function* zip(...its) { async function* iter(it) { for await (let x of it) yield x } its = its.map(iter) while (true) { let rs = await Promise.all(its.map(it => it.next())) if (rs.some(r => r.done)) return yield rs.map(r => r.value) } } // demo: let delay = (a, n) => { console.log('begin', a) return new Promise(r => setTimeout(() => { console.log('resolved', a) r() }, n)) } class Test { constructor(start) { this.start = start } async* [Symbol.asyncIterator]() { for (let i = 1; i < 10; i++) { await delay(this.start, Math.random() * 1000) yield this.start + i } } } async function main() { let iters = [ new Test('a'), new Test('b'), new Test('c'), ] for await (let x of zip(...iters)) console.log('ZIP', ...x) } main()