有一个异步迭代
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])
}
}
}
}
我想做这样的事情。
for await (const i of zip(new Fasta(args.filea), new Fasta(args.fileb))) {
// do the work
}
我发现了几个 walkarouds here,但它们似乎都基于 Array.map()。通过这种方式,我需要创建一个数组来携带所有数据。当文件很大时,就会出错。
我试过了
async function * zip(fasta1, fasta2) {
for await (const [i,j] of [fasta1, fasta2]) {
yield [i,j]
}
}
但它给了我一个“TypeError: .for is not iterable”。
任何帮助将不胜感激!
答案 0 :(得分:2)
这是我的答案 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()