New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ability to use Observables with async/await #83
Conversation
@zenparsing Please take a look when you can. I'm hoping to get this change in so it can be used upstream by Apollo GraphQL. |
@zenparsing fixed merge conflict |
Adding support for But it would be cool - I'll give it some thought. |
Currently, you have to do something like this, right? let list = [];
await observable.forEach(value => list.push(value));
for (const value of list) {
// loop body...
} or await observable.forEach(value => {
// loop body...
}); |
Similar but yes. That all data will be retrieved beforehand is called out in the notes. It is set up as an asyncIterator so it’s used with
If the user wants to traverse the values as they arise the traditional methods still apply. Same as with the promisify() method. It gets all values in order and returns them in a promise fulfilled array. Again, traditional methods still apply. These add only an opportunistic functional add for those who know the data coming. If the wait is a network request or two, one would have to wait regardless. So getting that data with a single line of code is nice. |
If we wanted to support So I understand correctly, can you give an example where: await observable.forEach(value => {
// loop body...
}); does not work? |
Wow, I will admit that I did not expect
|
I'll address the package-lock issues once I know whether or not the PR has legs. @zenparsing |
@nyteshade It's definitely not an obvious part of the API, although it's old and dates back to the original JS proposal 😄 It still might be nice to add something like the for (const value of await observable.all(()) {
// Loop body...
} |
All is fine and I can make that change. What would you like to do about the iterator? Keep it or kill it? |
@zenparsing test and function updated with the name |
@@ -315,6 +315,26 @@ export class Observable { | |||
})); | |||
} | |||
|
|||
async all() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can all
just be this?
async all() {
let values = [];
await this.forEach(value => values.push(value));
return values;
}
src/Observable.js
Outdated
return promise; | ||
} | ||
|
||
async *[Symbol.asyncIterator]() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With all
, can we just do this?
for (const value of await observable.all()) {
// Loop body...
}
I'd like to defer adding Symbol.asyncIterator
because of the buffering issues.
test/all.js
Outdated
let observable = Observable.of(1,2,3,4); | ||
let values = await observable.all(); | ||
|
||
assert.deepEqual([1,2,3,4], values); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The actual value should come first, and the expected value second, so:
assert.deepEqual(values, [1,2,3,4]);
.babelrc
Outdated
@@ -0,0 +1,25 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's leave out these changes to babel etc. in this PR. I'm going to upgrade the package to ESM and get rid of all this babel junk.
Sorry for all of the conflicts. If this PR just adds the |
README.md
Outdated
@@ -174,3 +174,31 @@ Observable.of(1, 2, 3).concat( | |||
``` | |||
|
|||
Merges the current observable with additional observables. | |||
|
|||
### observable.promisify() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can leave out this change - I'll update the README after merge.
A lot of modern JavaScript code uses async/await to handle asynchronous code. This is a great way to write code that is easy to read and understand. However, it is not possible to use async/await with Observables outside of the `forEach()` which requries more boilerplate than needed in order to do so. Changes: * Adds `.all()` to an observable instance allowing one to `await` the values it contains * Adds a test for the new functionality
Thanks - will push a new version soon. |
As you wish, though I spent more time than I'd like to admit fixing the babel stuff, lol. Et voila, you have it,
It should be as you like now. |
@zenparsing btw, when I ran |
I was wondering about that, so I bumped the version to |
I guess technically in SemVer 0.9.0 is a backwards compatible feature release. To indicate breaking changes, a bump from 0.8.15 to 1.0.0 would be required. If there is a way to generate non-class based output you could do a 0.9.1 release. Then save the class based output until you remove transpilers and do a 1.0 release @zenparsing |
I can try to coax Babel into doing so unless you have an older version of node. I’m on a M1 Mac so I need to use Rosetta to get older node versions running. |
Oh actually, @zenparsing, the behavior changed in this commit d3d16f2. It uses es2018 for output which will use classes because the whole world today supports them. I would recommend undoing that until you move to a 1.0.0 release. As it will break dependencies that incorrectly rely on |
A lot of modern JavaScript code uses async/await to handle asynchronous code. This is a great way to write code that is easy to read and understand. However, it is not possible to use async/await with Observables outside of the
forEach()
which requries more boilerplate than needed in order to do so.Changes:
.all()
to an observable instance allowing one toawait
the values it contains