There is an async iterable
JavaScript
x
35
35
1
class Fasta {
2
//read file line by line and yield a class based on every four lines
3
constructor(path) {
4
this.path = path
5
const filestream = fs.createReadStream(this.path)
6
if (this.path.match(/(.fastq)|(.fq)$/)) {
7
this.filetype = 'fastq'
8
this.handle = readline.createInterface({
9
input: filestream,
10
crlfDelay: Infinity
11
})
12
} else if (this.path.match(/.gz$/)) {
13
this.filetype = 'fqgz'
14
this.handle = readline.createInterface({
15
input: filestream.pipe(zlib.createGunzip()),
16
crlfDelay: Infinity
17
})
18
}
19
}
20
async * [Symbol.asyncIterator]() {
21
let counter = 0
22
const rec = {0: '', 1: '', 2: '', 3: ''}
23
for await (const line of this.handle) {
24
if (counter < 3) {
25
rec[counter] = line.trim()
26
counter +=1
27
} else if (counter == 3) {
28
rec[counter] = line.trim()
29
counter = 0
30
yield new Dna(rec[0], rec[1], rec[3])
31
}
32
}
33
}
34
}
35
and I want to do someting like this.
JavaScript
1
4
1
for await (const i of zip(new Fasta(args.filea), new Fasta(args.fileb))) {
2
// do the work
3
}
4
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
JavaScript
1
6
1
async function * zip(fasta1, fasta2) {
2
for await (const [i,j] of [fasta1, fasta2]) {
3
yield [i,j]
4
}
5
}
6
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:
JavaScript
1
53
53
1
async function* zip(its) {
2
3
async function* iter(it) {
4
for await (let x of it)
5
yield x
6
}
7
8
its = its.map(iter)
9
10
while (true) {
11
let rs = await Promise.all(its.map(it => it.next()))
12
if (rs.some(r => r.done))
13
return
14
yield rs.map(r => r.value)
15
}
16
}
17
18
// demo:
19
20
let delay = (a, n) => {
21
console.log('begin', a)
22
return new Promise(r => setTimeout(() => {
23
console.log('resolved', a)
24
r()
25
}, n))
26
}
27
28
class Test {
29
constructor(start) {
30
this.start = start
31
}
32
33
async* [Symbol.asyncIterator]() {
34
for (let i = 1; i < 10; i++) {
35
await delay(this.start, Math.random() * 1000)
36
yield this.start + i
37
}
38
}
39
}
40
41
async function main() {
42
let iters = [
43
new Test('a'),
44
new Test('b'),
45
new Test('c'),
46
]
47
48
for await (let x of zip(iters))
49
console.log('ZIP', x)
50
}
51
52
53
main()