Skip to content
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 support for Each extension #28

Closed
mcudich opened this issue Feb 26, 2018 · 4 comments
Closed

Add support for Each extension #28

mcudich opened this issue Feb 26, 2018 · 4 comments

Comments

@mcudich
Copy link

mcudich commented Feb 26, 2018

While the All extension is useful for parallel execution of promises, it would be useful to also have a mechanism that ensures serial execution of promises.

Something like:

[FBLPromise each:@[p1, p2, p3, ...]] that returns a promise that is resolved when all supplied promises resolve in order.

See http://bluebirdjs.com/docs/api/promise.each.html for an example of how this might be handled.

I think copying Bluebird's behavior here is probably fine.

We basically want a mechanism where we can supply an array of promises, execute them one at a time serially, and then be able to chain an additional promise to be executed when this set of promises is done.

This kind of mechanism allows building more generalized chains, where you can have many serial chains executed in parallel (where you would wrap an array of "each" chains in an "all" chain), and parallels chains executed in serial order.

@shoumikhin
Copy link
Contributor

shoumikhin commented Feb 28, 2018

Hi Matias,

Many thanks for the suggestion! Unfortunately, even if we added something similar to each, that probably wouldn't work for the case you've mentioned.

The issue with all is that it expects a sequence of promises, which means some of the promises in such sequence may potentially get resolved concurrently on different queues before they were even passed to all or before all had a chance to subscribe for them and observe for state changes.

To guarantee serial resolution of promises you'd need to create them serially. Presumably, something like the following template would work for your scenario:

Swift:

values.reduce(initialPromise) { previousPromise, currentValue in
  previousPromise.then { previousValue in
    // Do something with the previous and current values to compute the next value.
    return nextValue
  }
}.then { resultingValue in
  // Do something with the resulting value.
}

Objective-C (powered with FBLFunctional):

[[values fbl_reduce:initialPromise
            combine:^FBLPromise *(FBLPromise *previousPromise, id currentValue) {
              return [previousPromise then:^id(id previousValue) {
                // Do something with the previous and current values to compute the next value.
                return nextValue;
              }];
            }] then:^id(id resultingValue) {
              // Do something with the resulting value.
              return sum;
            }];

A naive example:

Swift:

[1, 2, 3].reduce(Promise(0)) { promise, number in
  promise.then { partialSum in
    partialSum + number
  }
}.then { sum in
  print(sum)
}

Objective-C:

[[@[@1, @2, @3] fbl_reduce:[FBLPromise resolvedWith:@0]
                   combine:^FBLPromise *(FBLPromise *promise, NSNumber *number) {
                      return [promise then:^id(NSNumber *partialSum) {
                        return @(partialSum.integerValue + number.integerValue);
                      }];
                   }] then:^id(NSNumber *sum) {
                     NSLog(@"%@", sum);
                     return sum;
                   }];

Please, let us know if that doesn't work for you or if you have any further ideas or suggestions.

Thanks!

@jkmassel
Copy link

I would like to (posthumously?) +1 this issue on the off chance others are doing what I'm doing - currently I use following hack to ensure that parent objects sync before child objects (I don't need to pass data down the chain, but I do care about deterministic order of operations):

RequestFactory(forEntity: Post.self, operations: [.create])
.then { (nothing) -> Promise<Void> in
  return RequestFactory(forEntity: Comments.self, operations [.create])
}

It would be lovely to have some sort of syntactic sugar around this, even if it was in an "advanced" section and had a big warning about "here be dragons" or something. I'd be happy to help clarify anything above if needed.

Thanks very much for your work on this library, it is delightful to use.

@shoumikhin
Copy link
Contributor

Hi Jeremy, absolutely, any suggestions on such syntactic sugar and usage examples are highly appreciated! We strive to constantly improve this lib.

@ghost
Copy link

ghost commented Apr 19, 2018

Replying to Matias' comment: "We basically want a mechanism where we can supply an array of promises, execute them one at a time serially, and then be able to chain an additional promise to be executed when this set of promises is done."

You should be able to more easily accomplish this with the newly added reduce operator:
https://github.com/google/promises/blob/master/g3doc/index.md#reduce

Please let us know if you have any additional questions or suggestions on how we can improve our API. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants