-
Notifications
You must be signed in to change notification settings - Fork 147
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
Async mapping with promises #517
Comments
Might be interesting to extend |
-1 on this. It's not _([1,2,3,4]).flatMap(id => hl(db.getUserFromId(id))).each(user => {
console.log(` - ${user.name}`)
}) That said maybe some equivalent to |
@svozza Thanks for the example, and I get the point you ar making. You're right. Some thing like |
@samvv We accept PRs 😉. |
Porting |
I'm working on this. Is there a preference for extending wrapCallback vs adding a new wrapPromise function? |
There should be a new |
You can call the passed function and check for a .then function afterwards, which is what I did in my pull request. I am happy to break out the logic into separate functions. I was trying to mimic the asyncify function referenced in this thread. Also, I cut the branch from 2.x but I'm wondering if this work should actually be done on master? |
Oh, I see what you wanted to do. That's not the functionality intended here. The stream constructor already does that. What we want is a way to wrap a function that returns a promise and turn it into an equivalent function that returns a stream. You won't need much of the logic from
This should be done on master, yes. Only bugfixes and documentation fixes go on * This was a new function in 2.10, but we accidentally did not expose it in the docs before now. |
Now that I think about it, it would be trivial to extend Is this worth doing? @svozza? |
Yes, sounds good. Would we deprecated |
I don't think so. The problem is there's no way to tell whether or not a function is meant to be called with a callback or not without the caller actually telling us. Deprecating |
Good point. The only issue though is that there will be a mismatch between the behaviour of |
Oh, that's tricky. I forgot about Alright, let's just bail on this idea. It's not like there's demand for support for the other types, and simplicity is best. We'll just stick with just support for promises. Though call it Then adding |
@vqvu You don't think calling the function and checking if it returns an object with a .then property is a good way to do that?
I'm not sure that I follow along with you here. Did you see my pull request? This is what I thought I was doing so now I'm a little confused. Are you saying that the constructor already detects a promise and converts it to a stream?
I agree that just supporting promises and callbacks is probably fine for now. I'm not sure about naming the promise handler |
Sorry, I wasn't being clear. The problem with your PR isn't the way that it detects a promise. The problem is that it passes a callback all the time. var result = f.apply(self, args.concat([cb])); This is not OK because people write varargs functions and functions with optional arguments. Here's an example of a bad case, function doAThing(optionalString) {
var result = optionalString || 'default';
return new Promise((res, rej) => {
res('The result is: ' + optionalString);
});
}
var doAThingStream = wrapCallback(doAThing);
doAThing().then(x => {
// x === 'The result is: default'
});
doAThingStream().toArray(xs => {
// xs !== ['The result is: default']
// This is bad.
}); When I say "There's no way to tell the difference", I am refering to this problem. We cannot pass the callback unless we know for sure that the Currently, the fact that someone is using
I misread your PR when I made that comment. Feel free to ignore.
Yes. You can do
Furthermore, I don't like the |
There is prior art for the |
@vqvu Thanks for the detailed response, I appreciate you taking the time to answer my questions.
I had not considered this use case, it makes sense now.
Understood. My confusion is that I thought this was the functionality being requested.
Good point. Should I name it wrapAsync for now and change it to streamifyAsync if we add the streamify alias for wrapCallback? I'm happy to add the alias as part of this work too I'm just not sure where we landed on it. |
Yes. Let's just start with |
I have been using wrapAsync pretty successfully and was wondering if it would make sense to support a node 8 AsyncFunction under the same API (one that gets generated using async keyword)? |
As far as I know, |
It did not work @vqvu, in fact I ended up spending 2-3 hours debugging this as my code wasn’t covered with tests and I had converted parts of it to asyncawait a week ago. My usecase entailed something like below: highland(something).batch(1000).map(wrapAsync(promiseReturningFunction)) All I did was change the promiseReturningFunction to an asyncFunction. Would I need more changes on the highland processing chain? |
If it worked before, it should still work now unless you have some sort of race condition going on. Maybe you were implicitly relying on some specific execution order? Can you provide a test case that fails? I tried this simple pipeline in node 8.9.0 and didn't see an issue const _ = require('highland');
function stream() {
let i = 0;
return _((push, next) => {
if (i < 10) {
setTimeout(() => {
push(null, i++);
next();
}, i * 50);
} else {
push(null, _.nil);
}
});
}
function delay(x) {
return new Promise((resolve) => setTimeout(resolve, x));
}
function promiseReturning(array) {
return delay(1000).then(() => array[0] + array[1]);
}
async function asyncFunction(array) {
await delay(1000);
return array[0] + array[1];
}
stream()
.batch(2)
.map(_.wrapAsync(promiseReturning))
.merge()
.toArray(x => console.log(`promiseReturning: ${x}`));
stream()
.batch(2)
.map(_.wrapAsync(asyncFunction))
.merge()
.toArray(x => console.log(`asyncFunction: ${x}`)); |
|
I don't know if it has been asked before (could only find issue #313, which doesn't cover promises), but it would be really neat if mapping would work with promises, such as this:
Doing this would make, in my eyes, the library a lot more powerful. Also see is-promise for a predicate which determines if a returned value is a promise.
Is this worth debating?
The text was updated successfully, but these errors were encountered: