rubico
Version:
[a]synchronous functional programming
85 lines (74 loc) • 2.02 kB
JavaScript
const promiseRace = require('./promiseRace')
const __ = require('./placeholder')
const curry2 = require('./curry2')
const isPromise = require('./isPromise')
const LinkedList = require('./LinkedList')
const symbolAsyncIterator = require('./symbolAsyncIterator')
const arrayPush = require('./arrayPush')
const sleep = require('./sleep')
/**
* @name MappingAsyncIterator
*
* @synopsis
* ```coffeescript [specscript]
* mappingAsyncIterator = new MappingAsyncIterator(
* asyncIter AsyncIterator<T>,
* mapper T=>Promise|any,
* ) -> mappingAsyncIterator AsyncIterator
*
* mappingAsyncIterator.next() -> Promise<{ value: any, done: boolean }>
* ```
*/
const MappingAsyncIterator = (asyncIterator, mapper) => {
const buffer = new LinkedList()
let index = -1
let consumingAsyncIterator = false
let isAsyncIteratorDone = false
return {
[symbolAsyncIterator]() {
return this
},
// _consumeAsyncIterator() -> Promise<>
async _consumeAsyncIterator() {
for await (const item of asyncIterator) {
index += 1
const mappedItem = mapper(item)
buffer.append(mappedItem)
}
isAsyncIteratorDone = true
},
/**
* @name next
*
* @synopsis
* ```coffeescript [specscript]
* next() -> Promise<{ value, done }>
* ```
*/
async next() {
if (!consumingAsyncIterator) {
this._consumeAsyncIterator()
consumingAsyncIterator = true
}
while (!isAsyncIteratorDone) {
if (buffer.length > 0) {
let value = buffer.popFirst()
if (isPromise(value)) {
value = await value
}
return { value, done: false }
}
await sleep(10)
}
if (buffer.length > 0) {
let value = buffer.popFirst()
if (isPromise(value)) {
value = await value
}
return { value, done: false }
}
return { value: undefined, done: true }
},
}
}
module.exports = MappingAsyncIterator