async-from-sync
TypeScript icon, indicating that this package has built-in type declarations

1.0.9 • Public • Published

async-from-sync

Using async for-await-of loop to iterate over sync generator is possible, but can cause strange effects in some edge cases (https://bugzilla.mozilla.org/show_bug.cgi?id=1610315).

This is not a problem if you are developing an app because you know what kind of iterable you have and can use the appropriate loop.

But if you are developing a library it can be nice to have the same code to work with both sync and async input. So there is a choice between a simpler code with one for-await-of loop which works for most cases but not all and more complex code with type checking and two loops for-of and for-await-of.

This module lets you have one loop which just works.

// The following finally section will never be called if generator
// is consumed by for-await-of:
function* generator() {
  try {
    yield Promise.resolve(42)
    yield Promise.reject(43)
  } finally {
    console.log('finally')
  }
}
 
for await (const x of generator()) {
  console.log(x)
}
// 42
// Error thrown: 43
 
// But if you iterate over that generator with sync for-of loop
// and await yielded promise inside that loop, then finally is called
// as expected:
for (const x of generator()) {
  console.log(await x)
}
// 42
// finally
// Error thrown: 43

Let's fix that:

import { iteratorWrap } from 'async-from-sync'
 
function* generator() { ... }
 
for await (const x of iteratorWrap(generator())) {
  console.log(x)
}
// 42
// finally
// Error thrown: 43

The same applies to yield* operator if used with sync iterables.

API

asyncFromSync(iterator: Iterable): AsyncIterable

Converts sync iterator to async one in the right way.

asyncWrap(iterator: Iterable | AsyncIterable): AsyncIterable

Returns async iterator. Does convertion if sync iterator is passed.

iteratorWrap(iterator: Iterable | AsyncIterable): Iterable | AsyncIterable

Does conversion only if needed. Does not any conversion if javascript engine always calls finally blocks of generators. Useful if you need to have a thing that just works:

async function F() {
  for await (const x of iteratorWrap(someIterable)) { ... }
}
async function* G() {
  yield* iteratorWrap(someIterable)
}

Package Sidebar

Install

npm i async-from-sync

Weekly Downloads

2

Version

1.0.9

License

MIT

Unpacked Size

14.9 kB

Total Files

24

Last publish

Collaborators

  • vadzim