An open API service indexing awesome lists of open source software.

https://github.com/re-quant/rxjs-awaitable-observables

๐Ÿงจ This package makes async/await working with Observables without .toPromise() ๐Ÿ’ฅ
https://github.com/re-quant/rxjs-awaitable-observables

angular async-await nestjs promise rxjs ts typescript

Last synced: about 2 months ago
JSON representation

๐Ÿงจ This package makes async/await working with Observables without .toPromise() ๐Ÿ’ฅ

Awesome Lists containing this project

README

        

# RxJS Awaitable Observables



Build status


NPM version


Code Coverage


License: GPL v3

๐Ÿงจ ย ย  ๐Ÿ’ฅ ย ย  ๐Ÿ’ช ย ย  Use async/await with any RxJS stream and be happy ย ย  โœ… ย ย  ๐Ÿ‘จโ€๐Ÿ’ป ย ย  ๐Ÿ˜Ž

Zero third-party dependencies

ย 


Notice: If you have any propositions feel free to make an issue or create a pull request.

![IDE Demo](/resources/ide-demo.png)

## Installation

### 1. Install the package

`yarn add @z-brain/rxjs-awaitable-observables`
or
`npm i -s @z-brain/rxjs-awaitable-observables`

### 2. Add the import line of the package to your entry .ts files

Your `main.ts`:
```typescript
import '@z-brain/rxjs-awaitable-observables';
```

That is all ๐Ÿ™‚ย  Feel free to use async/await with observables ๐Ÿ˜‰

**Detailed description:**

* In case of Angular project it can be `main.ts`
* In case of a server project it is the entry file of your server app (`index.ts` or `server.ts` in most cases)

### 3. Configure you testing framework

If you are going to use async/await with observables in any kind of your tests (unit / e2e) there are two ways to do it:

1. Add a setup file with the import to you testing framework. In case of `Jest` it can be done via `setupFiles` or `setupFilesAfterEnv`. **(recommended)**

```javascript
// jest.config.js
module.exports = {
...
setupFiles: [ './jest.setup.ts' ],
...
};

// jest.setup.ts
import '@z-brain/rxjs-awaitable-observables';
```
2. Or you can manually import the package to each of your test **(unrecommended)**

## Usage examples

**1. Simple example: async/await works with completed observables**

```typescript
const value$ = $$.of(123);
const value = await value$;
expect(value).toBe(123);
```

**2. Take the first value in the stream**
```typescript
const value$: Observable = $$.of(111, 222, 333);
const value = await value$;
expect(value).toBe(111);
```

**3. Takes the last value of a completed stream**
```typescript
const value$: Observable = $$.of(111, 222, 333);
const value = await value$.pipe($.last());
expect(value).toBe(333);
```

**4. Take the initial value of `Subject` + `.startWith()`**
```typescript
const newValues$: Observable = new Subject();
const value$ = newValues$.pipe($.startWith(123));

const value = await value$;
expect(value).toBe(123);
```

**5. Take the first value of `ReplaySubject`**
```typescript
const value$ = new ReplaySubject(2);
value$.next(111);
value$.next(222);
value$.next(333);
value$.next(444);

const value = await value$;

expect(value).toBe(333);
```

**6. Error handling using try/catch**
```typescript
const MSG = 'Something went wrong';
const err$ = $$.throwError(new Error(MSG));

try {
await err$;
} catch (e) {
expect(e.message).toMatch(MSG);
}
```

**7. throw an EmptyError on completing observable without a message**
```typescript
const emptyStream$ = $$.EMPTY;

try {
await emptyStream$;
} catch (e) {
expect(e).toBeInstanceOf(EmptyError);
}
```

**8. Manually .then() call (Promises integration)**
```typescript
const value$: Observable = $$.of(123);

const promise = Promise.resolve(10)
.then(multiplier => value$.then(v => v * multiplier));

return expect(promise).resolves.toBe(1230);
```

## How does it work?

* This package patches `Observables`'s prototype and adds `.then()` method to make all `Observable`s and its children work with `async`/`await` as is without the necessary to call `.toPromise()`
* Yes, the package patches .prototype of another package (RxJS).
In theory, it can be dangerous. However, this package does it enough carefully.
We already saw some successful examples of patching .prototype even build-in functions. (Zone.js for example)
I suggest don't afraid and make our daily work easier and our code more beautiful.

**100% test coverage**:
```
async/await tests
โœ… async/await should work with completed observables
โœ… Should take the first value in the stream
โœ… Should take the last value of a completed stream
โœ… Should take the current value of BehaviorSubject
โœ… Should take the initial value of Subject + .startWith()
โœ… Should take the first value of ReplaySubject
โœ… try/catch should handle an error from the stream via async/await
โœ… Should throw an EmptyError on completing observable without message
Check integration with Promises
โœ… Should work with manually .then() call
โœ… Empty .then() call should just return a promise with the value without any errors
โœ… In case of error in the stream empty .then() call should do nothing and return rejected promise with the error

```

## Development notes

### Quick Start

```bash
cd /code/z-brain
git clone [email protected]:z-brain/rxjs-awaitable-observables.git
cd rxjs-awaitable-observables
yarn install
```

### How to use NodeJS version from the `.nvmrc`

1. Install NVM
2. Use `.nvmrc` file one of the next ways:

* Execute `nvm use` in the project root directory
* Install [NVM Loader](https://github.com/korniychuk/ankor-shell) and your .nvmrc will be loaded automatically when you open the terminal.
![NVM Loader demo](./resources/readme.nvm-loader.png)

### How to make a build

`npm run build`

### How to run lint

* Just show problems `npm run lint`
* Fix problems if it is possible `npm run lint:fix`

### How to run tests

* All tests

`npm run test`
`npm run test:watch`
* Specific tests

`npm run test -- src/my.spec.ts`
`npm run test:watch -- src/my.spec.ts`

### How to build and publish NPM package

*NPM Token:* `3240...1349`

CI configuration details here: [.github/workflows/npmpublish.yml](.github/workflows/npmpublish.yml)

```bash
npm run pre-push
&& npm version patch -m 'Update package version version to %s'
&& npm run gen-public-package.json
&& cp README.md dist/
&& npm publish dist --access public
&& git push --no-verify && git push --tags --no-verify
```

### How to build package to local installation

1. `yarn run build:local`
2. Then you can install a local package build from path `file:.../rxjs-awaitable-observables/dist`.

## Author

| [
Anton Korniychuk](https://korniychuk.pro) |
| :---: |