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

Feature request #134

Open
wsdwsd0829 opened this issue Jan 8, 2020 · 9 comments
Open

Feature request #134

wsdwsd0829 opened this issue Jan 8, 2020 · 9 comments

Comments

@wsdwsd0829
Copy link

I have this list of promises chained by then, while current then will dispatch async to main to next runloop, while we want the work to be done immediately/inplace when some condition is met.
Say user type on keyboard and triggered the list of promises to be chained, while we want the the work of then to be called synchronously instead of just return. sth like

if(IsOnMain && promise.isFulfilled) { workOfThen()}

Is there a way to expose api like a synchronousThenIfPossible? Thanks

@Adlai-Holler
Copy link

Totally agreed, some way to handle cases where a promise has already resolved before reaching us (possibly a +resolvedWith:), and we are on main, being able to proceed immediately would be insanely useful. @property(nullable, readonly) id valueIfResolved and errorIfRejected would be a straightforward API.

@wsdwsd0829
Copy link
Author

https://github.com/google/promises/blob/master/Sources/FBLPromises/FBLPromise.m#L235 if we have a way to not always dispatch_group_async here, and I do not see the need for dispatch group if we do not need waiting? and it seems only need waiting for testing purpose?

@nsoojin
Copy link
Contributor

nsoojin commented Jan 10, 2020

I think what you're looking for is await?
It will make you wait for the promise to be fulfilled(thus, synchronous).

@Adlai-Holler
Copy link

Await will not work because the “then” method uses the main queue, and main queue wont drain while we wait and we’ll be stuck forever.

@nsoojin
Copy link
Contributor

nsoojin commented Jan 10, 2020

Of course you shouldn't use await on main queue. Why can't you use a custom background queue?

numberPromise.then(on: backgroundQueue) { number in
  return String(number)
}

@wsdwsd0829
Copy link
Author

wsdwsd0829 commented Jan 10, 2020

say click a like button and we want to update the ui immediately then the promise1 we want it to be sync to run some logic and spit out the result of update like or not. then another promise2 after promise1 will dispatch to background as a "then" of promise 1.

Another similar example is that we override TextView's
-(BOOL) shouldChangeText {
promise1.then { return promse2 } .
return promise1's value;
} . // the promise1 need to be resolved (blocking/synchronously) to make sure the return is valid value instead of async.

Also we do not have control of promise1 (user provide that) meaning we can not just use [Promise resolvedWithValue];

@nsoojin
Copy link
Contributor

nsoojin commented Jan 10, 2020

If you disclose the full source code, it will be more helpful.
But from what you said, I think you are trying to block the main queue, which you should never do.

You shouldn't be using promise if you need the value synchronously on the main queue. Because by definition, you don't know how long the promise will take to be resolved.

@shoumikhin
Copy link
Contributor

Hi Max,

From what you've described, it seems like you're trying to use a promise to implement a synchronous method (which happens to be a predefined delegate call, so you can't just make it async), so have to really wait for the result somehow.

As I understand, await on a background queue cannot be used, because it'd block the same queue the ultimate promise was dispatched on, so it'll deadlock in case the promise is still pending.

More context for your example would definitely help. It's unclear where that promise1 and promise2 in shouldChangeText come from, how exactly they're normally supposed to be resolved and why they're used to implement a synchronous method, where you could just do the work directly and skip using promises altogether.

Alternatively, you may consider storing the promise result somewhere when it's resolved for the first time and check that value instead in a delegate method, since any promise resolves only once.

The reason why Promises doesn't support direct queries like isFulfilled or isRejected (other that in tests, where those are used carefully to prove a promise has a particular state after the action) is because those calls are usually quite error-prone:

  • They may lead to race conditions. You can technically have two myPromise.isFulfilled on one line of code and get different results.
  • They provoke a generally bad design. E.g. some people may start pooling a promise with a timeout instead of using then, etc.

Actually, consider completion handlers. Those should always be @escaping and get invoked asynchronously, even if in some trivial cases it's pretty tempting to call a completion handler with a value we already have handy instead of dispatch_async it. Because the very presence of a completion handler implies the method is asynchronous and the caller can safely assume the handler is never invoked before the control leaves the method. Now, Promises is just a more convenient way to implement completion handlers: they simply have to be always async and you're not supposed to implement synchronous methods using them.

Thanks.

@ostryhub
Copy link

ostryhub commented Mar 3, 2021

I came here accidentally while looking for some promise libraries.
What I can add to this discussion is that I agree with the initial request from @wsdwsd0829.
Its pretty convenient to have a way of creating an already resolved promise in synchronous way, so that it can be included in a chain of async operations.
This may be useful for many reasons:

  • from testing your code with some fake data (injected into the chain with synchronously resolved promise)
  • to actually combining both async and sync available data into same promise chain

As an example of implementation please check this C# implementation of promises I use for Unity3D projects.
https://github.com/Real-Serious-Games/C-Sharp-Promise/blob/824b714b47e40239aa6595a3288460c461539345/src/Promise.cs#L1114

This allows for such synchronously available data inclusion into promise chain.

I hope I understood the initial issue idea correctly.
Cheers.

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

5 participants