Skip to main content

Finalization, and Resource Management

In particular, the async iterator may have to allocate resources such as database connections and file handles at the start of iterator enumeration, and discard resources when enumeration is completed or abnormally terminated. In other environments, this is called the Dispose pattern.

leseq uses finalize(finalizeAsync) operator to achieve this pattern.

const source = fromAsAsync([1, 2, 3, 4, 5]).pipe(
takeAsync(3),
finalizeAsync(async () => console.log('finalized'))
);

for await (const one of source) {
console.log(one)
}

//console: 1
//console: 2
//console: 3
//console: finalized

Finalize is always executed at the completion or abnormal end of an enumeration as long as the enumeration has started, whether it is a full enumeration in a for statement, a break in a for statement, toArray(), or outputting a value in value functions.

break case

const source = fromAsAsync([1, 2, 3, 4, 5]).pipe(
takeAsync(3),
finalizeAsync(async () => console.log('finalized'))
);

for await (const one of source) {
console.log(one)
if(one == 2) break;
}

//console: 1
//console: 2
//console: finalized

value case

const result = await fromAsAsync([1, 2, 3, 4, 5]).pipe(
takeAsync(3),
finalizeAsync(async () => console.log('finalized'))
).valueAsync(findAsync(async i => i == 2));

//result: 2
//console: finalized

error case

const result = await fromAsAsync([1, 2, 3, 4, 5]).pipe(
takeAsync(3),
tapAsync(async () => {throw new Error('test')}),
finalizeAsync(async () => console.log('finalized'))
).toArrayAsync();

//Error
//console: finalized

However, for those that do not actually enumerate at that time, such as asyncSeq(), finalize does not work either; if asyncSeq() starts enumerating, finalize will work at the end of enumeration or on an error.

const source = from([1, 2, 3]).pipe(
tap(() => {throw new Error('test')}),
finalize(() => {console.log('finalized')}),
).to(asyncSeq());

//no output

for await(const one of source) {
console.log(one);
}

//Error
//console: finalized

In addition, all finalizes work as expected even in such a compound case of iterable to async iterable and multiple finalizes.

const output = await from([1, 2, 3, 4, 5]).pipe(
tap(() => {throw new Error('test')}),
finalize(() => {console.log('iterable finalized')}),
).to(asyncSeq()).pipe(
takeAsync(4),
finalizeAsync(async () => {console.log('async iterable finalized')}),
).toArrayAsync();

//Error
//console: iterable finalized
//console: async iterable finalized