As indexWhere() searches through potentially large Lists to find the matching index, is this an async operation?
And if so is there some way to await it? e.g. similar to Future.forEach
Since the method does not return a Future but an int, then the method is synchronous:
https://api.dart.dev/stable/2.7.1/dart-core/List/indexWhere.html
I also want to point out that asynchronous code in Dart are not the same as the code is running in another thread. Since we are talking about finding a index inside a List, then you can be fairly sure that this operation can only be done in a single thread since we need to prevent modifications of the List when we are making the search.
Related
I can't seem to find anywhere whether complete and tryComplete are atomic operations on Promises in Scala. Promises are only supposed to be written to once, but if two tryCompletes happen concurrently in two different callbacks for example could something go wrong? Or are we assured that tryComplete is atomic?
First a quick note that success(...) is equivalent to calling complete(Success(...)) and tryComplete(...) is equivalent to complete(...).isCompleted.
In the docs it says
As mentioned before, promises have single-assignment semantics. As such, they can be completed only once. Calling success on a promise that has already been completed (or failed) will throw an IllegalStateException.
A promise can only complete once. Digging into the source code, DefaultPromise extends AtomicReference (ie. thread safe) and so all writes are atomic. This means that if you have two threads completing a promise, only one of them can ever succeed and it'll be whichever did so first. The other will throw an IllegalStateException.
Here's a small example of what happens when you try and complete a promise twice.
https://scastie.scala-lang.org/hTYBqVywSQCl8bFSgQI0Sg
Though apparently it seems one can circumvent the immutability of a Future by doing a bunch of weird casting acrobatics.
https://contributors.scala-lang.org/t/defaultpromise-violates-encapsulation/3440
One should probably avoid that.
In Flutter we use async await and Future, can someone explain that if we don't use another thread (which we can't in dart) and run the job on main UIThread only won't the app become choppy because even if we are waiting for the job to execute it will ultimately execute on UIThread only.
I somewhere read about isolates also. But cannot paint the exact picture. If someone can explain in detail.
I think you missed something when it comes to asynchronous methods in Dart.
Dart is a single-threaded programming language, Java or C# are multi-threaded programming languages, forget async as a new thread, it doesn't happen in Dart.
Dart is a single-threaded programming language. This means is that Dart can only run one instruction at a time, while Java could run multiple instructions concurrently.
As a rule, everything you do in Dart will start in UI-Thread. Whatever method you call in Dart, whether using sync, async, then, they will be running on UI-Thread, since Dart is a single thread.
In single-threaded languages like Javascript and Dart, an async method is NOT executed in parallel but following the regular sequence of events, handled by the Event Loop. There are some problems (I would give some approaches, as we will see below) if you run the following code in a multithreaded language where fetch will take some time to execute:
String user = new Database.fetch(David);
String personalData = new Database.fetch(user);
You will receive David's data in user, and after that, you will receive your data.
This will lock your UI, unlike languages like Java which have Threads, where you can perform this task in the background, on another thread, and the UI-Thread will run smoothly.
If you do this at Dart
String user = new Database.fetch(David);
String personalData = new Database.fetch(user);
user will be null in personalData, because the fetch event is a Future.
How to solve this in Dart?
String user = await Database.fetch(David);
String personalData = await Database.fetch(user);
For those who like a more functional paradigm (I don't like it) you can use then.
Database.fetch(David).then((user){
Database.fetch(user).then((personal){
String personalData = personal;
});
});
However, imagine that you have billions of data in that database, this heavy task will probably cause the animations on your screen to freeze, and you will see a jank in the user's UI, for that purpose isolates were invented.
Dart Isolates give you a way to perform real multi-threading in Dart. They have their own separate heaps(memory), and run the code in the background, just like the Threads of multi-threaded languages. I could explain how isolates work, but it would make this response very long, and the goal is just to differentiate asynchronous from multi-threaded methods.
A simple way to solve the problem above using isolates would be using compute.
Compute was created to facilitate the creation of isolates, you just pass the function and the data that this function will execute, and that's it!
Important to remember that compute is a Future, so you have to use await or then to get its result.
In our example, we could create a new thread and get its result when we finish by just calling compute like this:
String user = await compute(Database.fetch,David);
String personalData = await compute(Database.fetch,user);
Very simple, isn't it?
In summary:
Everything that waits some time to be completed, in Dart is called a "Future".
To wait for the result of a future to be assigned to a variable, use await or then.
The asynchronous methods (await and then) can be used to obtain a result from a Future, and are executed ON THE MAIN THREAD because Dart is single-thread.
If you want to run any function on a new thread, you can create an isolate. Dart offers an easy-to-use isolate wrapper called compute, where you only need to pass one method that will be processed and the data that will be processed, and it will return its result in the future.
NOTE: if you are going to use compute make sure you are using a static or top-level method (see that in the example I used Database.fetch it was no accident if you need to call Database().fetch or need to create an instance of it, means it is not a static method and will not work with isolates).
English is not my first language and I didn't want to write so much because of that, but I hope I helped differentiate between multi-threaded asynchronous programming from single-threaded asynchronous programming.
Are the function bodies passed to Future.onComplete(), and their closures, discarded and so garbage collected after they are called?
I ask because I'm writing an unbounded sequence of Future instances. Each Future has an .onComplete { case Failure(t)...} that refers to the previous known-good value from a previous Future. What I want to avoid is the total history of all Future results being kept in the JVM's memory because of references in closure bodies.
Perhaps Scala is more clever than this, but skimming the code related to execution contexts and futures isn't yielding much.
Thanks.
The class that normally implements Future and that you want to look at is DefaultPromise.
It contains mutable state that is being updated as the Future completes.
If you call onComplete and it has already been completed then it just schedules your callback immediately with the result. The callback is not recorded anywhere.
If you call onComplete while the result is not yet available, the callback is added to a list of "listeners".
When the result becomes available (someone calls complete on the promise), then all listeners are scheduled to run with that result, and the list of listeners is deleted (the internal state changes to "completed with this result")
This means that your callback chain is only being built up until the "upstream future" is incomplete. After that, everything gets resolved and garbage-collected.
"list of listeners" above is a bit of a simplification. There is special care being taken that these listeners do not end up referring to each-other, specifically to break reference loops that would prevent garbage collection to work when constructing futures recursively. Apparently this was indeed a problem in earlier versions.
The problem of leaks is solved by automatically breaking these chains of promises, so that promises don't refer to each other in a long chain. This
allows each promise to be individually collected. The idea is to "flatten"
the chain of promises, so that instead of each promise pointing to its
neighbour, they instead point directly the promise at the root of the
chain. This means that only the root promise is referenced, and all the
other promises are available for garbage collection as soon as they're no
longer referenced by user code.
We're testing JS apps with protractor and sometimes we get some randomly unstable tests. Sometimes the errors are Failed: stale element reference: element is not attached to the page document
Just a hunch but sometimes developers write the code like this
await element(await by.css('.pager-next')).click();
And sometimes like this
await element(by.css('.pager-next')).click();
Is either of these "more" correct? Is there any need for the inner await or does it make no difference? Could this be causing stale element reference errors?
await is only useful for functions that return a Promise. Of the three functions in your snippet, only one of them returns a Promise. (You can check what each of them returns in the Protractor api).
ElementFinder.click() returns a Promise.
element() returns an ElementFinder.
by.css() returns a ProtractorLocator.
Therefore, the only call that should have await on it is click(), which you have done correctly in your second snippet.
StaleElementReferenceException is typically caused when you keep a reference to an object that has been removed from the page, e.g. using ElementFinder.getWebElement(). This removal can be subtle sometimes. For example, Angular will sometimes invisibly remove an element from the DOM and quickly replace it with an identical-looking one. It's hard to tell that anything even changed, but from Webdriver's perspective, the element it had a reference to has disappeared.
I think a better practice would be not to be write locators like that. I'd leave awaits for functions involving the element.
I would have a locator written like this:
const myElement = element(by.css('.pager-next'));
And then using async/await in a function:
let clickMyElement = async function(){
await myElement.click();
};
If I have a function call that returns true or false as the condition of an if statement, do I have to worry about Swift forking my code for efficiency?
For example,
if (resourceIsAvailable()) { //execute code }
If checking for the resource is computationally expensive, will Xcode wait or attempt to continue on with the code?
Is this worth using a completion handler?
What if the resource check must make a database call?
Good question.
First off... can a function be used? Absolutely.
Second... should it be used?
A lot of that depends on the implementation of the function. If the function is known (to the person who wrote it) to take a long time to complete then I would expect that person to deal with that accordingly.
Thankfully with a lot of iOS things like that are taken out of the hands of the developer (mostly). CoreData and Network requests normally come with a completion handler. So any function that uses them would also need to be async and have a completion handler.
There is no fixed rule for this. My best advice would be...
If you can see the implementation of the function then try to work out what it’s doing.
If you can’t then give it a go. You could even use the time profiler in Xcode profiler to determine how long it is taking to complete.
The worst that could happen is you find it is slow and then change it for something else.