Comments (4)
Hi Teerapap, that sounds like an interesting idea!
Do you suggest that we parametrize the Promise.pending
(FBLPromise.pendingPromise
) constructor with a custom queue arg having DispatchQueue.promises
default value, store it within the promise and use in all convenience APIs that we currently have defaulting to DispatchQueue.promises
? That way once the promise is created with a custom queue, everything you chain on it would be dispatched on that custom queue you've specified initially.
Although, you'd need to explicitly fall back to the main queue at some point of the chain to update UI, for example. Also, make sure other users of your promise are aware anything they chain on it will be dispatched on some custom queue.
Is that what you'd expect?
from promises.
Hi shoumikhin,
Yes. Correct. Maybe explain with code is easier
Currently my code looks like this.
func callAPI(userId: String, on queue: DispatchQueue) -> Promise<Result> {
return Promise<Result> (on: queue) {
// call api
}.then(on: queue) {
return Result()
}
}
func register(user: String, on queue: DispatchQueue) -> Promise<Result> {
return Promise(on: queue) {
// do something
return db.getUserId(user)
}.then(on: queue) { userId -> Promise<Result> in
return callAPI(userId: userId, on: queue)
.always(on: queue) {
}
}.recover(on: queue) { error in
// do some error conversion
} // more then closures
}
register("username", on: DispatchQueue.global(qos: .userInitiated))
.always(on: DispatchQueue.main) {
// update UI on main queue
}.catch(on: DispatchQueue.main) {
// show error UI on main queue
}.then(on: DispatchQueue.main) {
// update UI on main queue
}
It would be better if I don't have to pass the queue down the line like this
func callAPI(userId: String, on queue: DispatchQueue) -> Promise<Result> {
return Promise<Result> (on: queue) {
// ....
}.then {
// run in the same queue as above
return Result()
}
}
func register(user: String, on queue: DispatchQueue) -> Promise<Result> {
return Promise(on: queue) {
// do something
return db.getUserId(user)
}.then { userId -> Promise<Result> in
// run on the same queue as above
return callAPI(userId: userId, on: queue)
.always {
// run on the same queue as specified in callAPI(...)
}
}.recover { error in
// run on the same queue as above
}
}
register("username", on: DispatchQueue.global(qos: .userInitiated))
.always(on: DispatchQueue.main) {
// update UI
}.catch(on: DispatchQueue.main) {
// show error UI
}.then(on: DispatchQueue.main) {
// update UI
}
from promises.
Hi Teerapap,
The thing is setting a queue per promise and using it for the rest of the chain is slightly trickier than it may seem initially. That approach is potentially quite error prone, since you're gonna pass a promise around and chain other blocks on it without clearly knowing which queue itβs run on.
I'd recommend to be explicit in each block, or rely on the well defined default, especially if the chain spans multiple methods throughout a class, or maybe even across classes. Otherwise, I imagine, in future you'd end up having some asserts or checks in each closure to guarantee it's indeed dispatched on a specific queue and other collaborators didn't suddenly mess things up.
Also, such change may introduce some issues with the existing code:
promise.then(on: queue) { /*...*/ }.then { /*...*/ }
The second then
above used to be dispatched on main
by default, but with the proposed change it's gonna be dispatched on a background queue
, which would be quite surprising for other clients.
Generally, it'd be very beneficial to follow a pattern when DB access, networking and other async APIs are always initiated from the main queue, but then internally use some dedicated background queues to do the real work. For example, you may have something like:
extension DispatchQueue {
static let diskIO: DispatchQueue = { DispatchQueue.global() }()
static let networkIO: DispatchQueue = { DispatchQueue.global() }()
static let utility: DispatchQueue = { DispatchQueue.global() }()
}
func callAPI(userId: String) -> Promise<Result> {
assert(Thread.isMainThread)
return Promise<Result>(on: .networkIO) {
// call API
}
}
func getUserId(_ user: String) -> Promise<UserId> {
assert(Thread.isMainThread)
return Promise<UserId>(on: .diskIO) {
// fetch records from DB
}
}
func register(user: String) -> Promise<Result> {
assert(Thread.isMainThread)
db.getUserId(user).then(callAPI).always(on: .utility) {
// ...
}.recover(on: .utility) { error in
// do some error conversion
} // more then closures
}
register("username").always {
// update UI on main queue
}.catch { error in
// show error UI on main queue
}.then { value in
// update UI on main queue
}
Please let us know if this is unclear or if you have any additional questions.
Thank you!
from promises.
Thanks for the explanation. I understand my suggestion will have issue with existing code.
and I understand your point of being explicit.
I don't think it will be error prone though because if I want to make sure a closure runs on specific queue, I would specify explicitly at the closure anyway to run on that queue.
The situation is sometimes I want to chain a closure that does not matter which queue it runs on. Ex.
.recover { error in
// convert error to some new error
throw newError
}
For this case, I think running it on the queue the pending promise running on (ex. .userInitiated or whatever) is more suitable than relying on default (which is usually main queue and high priority).
Your approach with .utility
, .networkIO
, .diskIO
queue is also acceptable.
Anyway, breaking the existing assumption is bad so please take it as a feedback for the next time.
Thanks
from promises.
Related Issues (20)
- Sometimes Post Request Timeout HOT 6
- FBLPromises crashing HOT 2
- Question. Is it possible to change the delay time between retrys?
- Bug in iOS 16 DevBeta1 HOT 13
- Extremely slow compile time of Objective-C files
- Contextual type for closure argument list expects 1 argument, which cannot be implicitly ignored
- Objective-C Promises crashes in SwiftUI previews HOT 2
- ios 16 strings convertible to NSError HOT 1
- FBLPromises fails to load building macos flutter app HOT 2
- 'NSInvalidArgumentException', reason: '-[FBLPromise HTTPBody]: unrecognized selector sent to instance HOT 1
- Confused when retry a Promise variable
- type(of: value) is NSError.Type HOT 1
- Bitcode Issue on Xcode 13 when disable it. HOT 1
- Question regarding implementation HOT 3
- Ignore a certain Error and terminate Promise HOT 5
- Please release a new version of promises that includes latest changes for Firebase HOT 4
- Builds including PromisesSwift failing on CI
- Build fails for macOS with Xcode 14.3
- Create releases for new versions HOT 1
- The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 12.0 to 17.0.99.
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from promises.