When we say "Effection is Structured Concurrency and Effects for
JavaScript", we mean "JavaScript" seriously. You shouldn't have to
learn an entirely new way of programming just to achieve structured
concurrency. That's why the Effection APIs mirror ordinary JavaScript
APIs so closely. That way, if you know how to do it in JavaScript, you
know how to do it in Effection.

The congruence between vanilla JavaScript constructs and their Effection
counterparts is reflected in the “Async Rosetta Stone.”

| Async/Await               | Effection         |
| --------------------------| ----------------- |
| `await`                   | `yield*`          |
| `async function`          | `function*`       |
| `Promise`                 | `Operation`       |
| `new Promise()`           | `action()`        |
| `Promise.withResolvers()` | `withResolvers()` |
| `Promise.allSettled()`    | `allSettled()`    |
| `using`                   | `using()`         |
| `await using`             | `using()`         |
| `for await`               | `for yield* each` |
| `AsyncIterable`           | `Stream`          |
| `AsyncIterator`           | `Subscription`    |

## `await` \<=> `yield*`

Pause a computation and resume it when the value represented by the right hand
side becomes available.

Continue once a promise has settled:

```javascript
await promise;
```

Continue when operation is complete.

```js
yield* operation;
```

## `async function` \<=> `function*`

Compose a set of computations together with logic defined by JavaScript syntax:

Count down from 5 to 1 with an async function:

```js
async function countdown() {
  for (let i = 5; i > 1; i--) {
    console.log(`${i}`);
    await sleep(1000);
  }
  console.log('blastoff!');
}
```

Count down from 5 to 1 with a generator function:

```js
import { sleep } from 'effection';

function* countdown() {
  for (let i = 5; i > 1; i--) {
    console.log(`${i}`);
    yield* sleep(1000);
  }
  console.log('blastoff!');
}
```

Both will print:

```
5
4
3
2
1
blastoff!
```

To call an async function within an operation use [`call()`][call]:

```js
import { call } from 'effection';

yield* call(async function() {
  return "hello world";
});
```

To run an operation from an async function use [`run()`][run] or [`Scope.run`][scope-run]:

```js
import { run } from 'effection';

await run(function*() {
  return "hello world";
});
```

## `Promise` \<=> `Operation`

The `Promise` type serves roughly the same purpose as the `Operation`. It is a
abstract value that you can use to pause a computation, and resume when the
value has been computed.

To use a promise:

```js
let result = await promise;
```

To use an operation:

```js
let result = yield* operation;
```

To convert from a promise to an operation, use [`until()`][until]

```js
import { until } from 'effection';

let operation = until(promise);
```

Adapting a _cancellable_ Promise API takes both halves: [`until()`][until] waits
for the promise, and [`useAbortSignal()`][use-abort-signal] binds the work that
promise represents to the lifetime of the current operation.

```javascript
import { until, useAbortSignal } from 'effection';

function* fetchUser(id) {
  let signal = yield* useAbortSignal();
  let response = yield* until(fetch(`/users/${id}`, { signal }));

  return yield* until(response.json());
}
```

to convert from an operation to a promise, use [`run()`][run] or [`Scope.run`][scope-run]

```js
import { run } from 'effection';

let promise = run(operation);
```

## `new Promise()` \<=> `action()`

Construct a reference to a computation that can be resolved with a callback.
In the case of `Promise()` the value will resolve in the next tick of the run
loop.

Create a promise that resolves in ten seconds:

```js
async function sleep_10s() {
  await new Promise((resolve) => {
    setTimeout(resolve, 10000)
  });
}
```

Create an Operation that resolves in ten seconds:

```js
import { action } from 'effection';

function* sleep_10s() {
  yield* action((resolve) => {
    let timeoutId = setTimeout(resolve, 10000);
    return () => clearTimeout(timeoutId);
  });
}

```

Key differences:

1. The promise executor will be executing eagerly and only ever once, but the
action body is executed every time (and only when) the action is evaluated.
2. The action executor must return a "finally" function that is run regardless
of whether action is resolved, rejected or discarded.

## `Promise.withResolvers()` \<=> `withResolvers()`

Both `Promise` and `Operation` can be constructed ahead of time without needing to begin the process that will resolve it. To do this with
a `Promise`, use the `Promise.withResolvers()` function:

```ts
async function main() {
  let { promise, resolve } = Promise.withResolvers();

  setTimeout(resolve, 1000);

  await promise;

  console.log("done!")
}
```

In effection:

```ts
import { withResolvers } from "effection";

function* main() {
  let { operation, resolve } = withResolvers();

  setTimeout(resolve, 1000);

  yield* operation;

  console.log("done!");
};
```

## `Promise.allSettled()` \<=> `allSettled()`

Wait for all operations to settle regardless of whether they succeed
or fail. Unlike [`all()`][all], [`allSettled()`][allSettled] never
short-circuits. Every result is represented as either `{ ok: true, value }` 
or `{ ok: false, error }`.

Wait for all promises to settle with `Promise.allSettled()`:

```js
let [user, comments] = await Promise.allSettled([
  fetchUser(id),
  fetchComments(id),
]);
```

Wait for all operations to settle with `allSettled()`:

```js
import { allSettled } from 'effection';

let [user, comments] = yield* allSettled([
  fetchUser(id),
  fetchComments(id),
]);
```

The shape of the results is slightly different from `Promise.allSettled()`.
Effection uses its [`Result<T>`][result] type so that settled results compose
the same way they do elsewhere in the library. You can construct these values
with [`Ok()`][ok] and [`Err()`][err].

## `using` \<=> `using()`

Bind a disposable to a block with the `using` declaration:

```js
async function main() {
  using conn = new Connection();
  await conn.send("hello");
} // conn[Symbol.dispose]() runs here
```

Bind a disposable to an operation with [`using()`][using]:

```js
import { using } from 'effection';

function* main() {
  let conn = yield* using(new Connection());
  yield* conn.send("hello");
} // conn[Symbol.dispose]() runs when the enclosing scope exits
```

## `await using` \<=> `using()`

Bind an async disposable to a block with `await using`:

```js
async function main() {
  await using conn = new Connection();
  await conn.send("hello");
} // await conn[Symbol.asyncDispose]() runs here
```

Bind an async disposable to an operation with [`using()`][using]:

```js
import { using } from 'effection';

function* main() {
  let conn = yield* using(new Connection());
  yield* until(conn.send("hello"));
} // conn[Symbol.asyncDispose]() is awaited when the enclosing scope exits
```

## `for await` \<=> `for yield* each`

Loop over an AsyncIterable with `for await`:

```js
for await (let item of iterable) {
  //item logic
}
```

Loop over a `Stream` with `for yield* each`

```js
import { each } from 'effection';

for (let item of yield* each(stream)) {
  // item logic
  yield* each.next();
}
```

See the definition of [`each()`][each] for more detail.

## `AsyncIterable` \<=> `Stream`

A recipe for instantiating a sequence of items that can arrive over time. It is not
the sequence itself, just how to create it.

Use an `AsyncIterable` to create an `AsyncIterator`:

```js
let iterator = asyncIterable[Symbol.asyncIterator]();
```

Use a `Stream` to create a `Subscription`:

```js
let subscription = yield* stream;
```

To convert an `AsyncIterable` to a `Stream` use the [`stream()`][stream]
function.

```js
import { stream } from 'effection';

let itemStream = stream(asyncIterable);
```

## `AsyncIterator` \<=> `Subscription`

A stateful sequence of items that can be evaluated one at a time.

Access the next item in an async iterator:

```js
let next = await iterator.next();
if (next.done) {
  return next.value;
} else {
  console.log(next.value)
}
```

Access the next item in a subscription:

```js
let next = yield* subscription.next();
if (next.done) {
  return next.value;
} else {
  console.log(next.value);
}
```

To convert an `AsyncIterator` to a `Subscription`, use the
[`subscribe()`][subscribe] function.

```js
let subscription = subscribe(asyncIterator);
```

[call]: /api/v4/call
[all]: /api/v4/all
[allSettled]: /api/v4/allSettled
[result]: /api/v4/Result
[ok]: /api/v4/Ok
[err]: /api/v4/Err
[until]: /api/v4/until
[use-abort-signal]: /api/v4/useAbortSignal
[run]: /api/v4/run
[scope-run]: /api/v4/Scope#interface_Scope-methods
[each]: /api/v4/each
[stream]: /api/v4/stream
[subscribe]: /api/v4/subscribe
[using]: /api/v4/using
