Silverlight: stop thread while waiting for user feedback - silverlight

Is it OK to stop current thread until user click some buttons in Silverlight? E.g.
var clicked = false;
ShowDialog(EventOnClosed => clicked = true);
while (!clicked) {};
return;
P.S. I know the right way. I'm just curious if there's a way to stop and then continue Silverlight execution flow.
P.P.S. Just to be more specific. Imagine a project where javascript alert() is used for messages. How do you replace "return Invoke("alert('')")" with Silverlight messageboxes? Do you change all 500 places to use the correct async technique?

No it isn't and you certainly won't want to tie up the CPU like that even if you do.
In Silverlight you really need to get used to programming in an asynchronous way.
void SomeContainingFunc(Action callBack)
{
ShowDialog(EventOnClosed => callBack()))
}
Whatever calls that and wants code to continue after the async operation is completed:-
void SomeCaller()
{
// ... do some intial stuff here
Action callBack = () =>
{
//.. code to happen after async call completed
}
SomeContainingFunc(callBack);
}

What you are attempting to do is halt (or more specifically pause) the UI thread - this is not a good idea in any circumstance, especially if you are waiting for the user to click something!
Just do it the "right way".

Related

Interval not causing re-render in react component

I am using the useEffect react hook to set an interval for a countdown variable. I have noticed that when the tab in my browser isn't active, the internal stops working. If the tab is active the code works exactly as expected.
Is there a better way to do this? Below is an example of the code.
export default function CountdownTimer({ minutes_left, action }) {
const [timeLeft, setTimeLeft] = useState();
function updateTimer() {
const remaining = ...work out time left
setTimeLeft(remaining);
}
useEffect(() => {
const interval = setInterval(() => {
updateTimer();
if (timeLeft.asMilliseconds() <= 0) {
action();
clearInterval(interval);
}
}, 1000);
return () => clearInterval(interval);
}, []);
return (
<p>{timeLeft}</p>
);
}
I have implemented solutions in Dan Abramov's post here about this problem. However Dan's solution's also don't render when the tab is inactive.
Note that this is how browsers work: inactive tabs are deprioritised and timers get heavily throttled. Remember that setTimeout and setInterval are most expressly not "run code once X ms have passed", they are "run code after at least X ms have passed" without any guarantee that things won't actually happen much, much later due to scheduling (e.g. whether the tab is active, or even visible as far as the OS can inform the browser) or even just because a bit of JS code took longer than your indicated interval to complete and so your timeout literally can't fire until it's done (because JS is single-threaded).
For Firefox, See https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API#Policies_in_place_to_aid_background_page_performance on what kind of throttling is performed on timers, and for Chrome, see https://developers.google.com/web/updates/2017/03/background_tabs
(For any other browser, a web search should find you similar documentation.)
However, think about what it means for a tab to become a background process: if your users can't see your tab, why would you need to update anything at all? Your users won't be able to see those updates. Instead, consider suspending purely visual tasks when a tab becomes invisible, and then resuming them when the tab becomes visible again, and using a clock-time check to determine whether "things need to happen".
In fact, this is important to do even on a foreground tab if you use setInterval or setTimeout: 10 consecutive setTimeout(..., 100) do not imply that it'll be exactly 1 second later once they're done, it means it's at least 1s later when we're done but we could easily reach that "one second later" mark by the time the 7th or 8th timeout fires because JS is single threaded, and if some task took a while, your timeout won't fire until that task is done. So you're going to at the very least need to update your code for that already anyway.
Probably because useEffect call use clearInterval function after the first render. Here's how the cleanup for useEffect works with the returned function - Example Using Hooks.

React - Old promise overwrites new result

I have a problem and I'm pretty sure I'm not the only one who ever had it... Although I tried to find a solution, I didin't really find something that fits my purpose.
I won't post much code, since its not really a code problem, but more a logic problem.
Imagine I have the following hook:
useEffect(() => {
fetchFromApi(props.match.params.id);
}, [props.match.params.id]);
Imagine the result of fetchFromApi is displayed in a simple table in the UI.
Now lets say the user clicks on an entity in the navigation, so the ID prop in the browser URL changes and the effect triggers, leading to an API call. Lets say the call with this specific ID takes 5 seconds.
During this 5 seconds, the user again clicks on an element in the navigation, so the hook triggers again. This time, the API call only takes 0,1 seconds. The result is immediatly displayed.
But the first call is still running. Once its finished, it overwrites the current result, what leads to wrong data being displayed in the wrong navigation section.
Is there a easy way to solve this? I know I can't cancel promises by default, but I also know that there are ways to achieve it...
Also, it could be possible that fetchFromApi is not a single API call, but instead multiple calls to multiple endpoints, so the whole thing could become really tricky...
Thanks for any help.
The solution to this is extremely simple, you just have to determine whether the response that you got was from the latest API call or not and only then except it. You can do it by storing a triggerTime in ref. If the API call has been triggered another time, the ref will store a different value, however the closure variable will hold the same previously set value and it mean that another API call has been triggered after this and so we don't need to accept the current result.
const timer = useRef(null);
useEffect(() => {
fetchFromApi(props.match.params.id, timer);
}, [props.match.params.id]);
function fetchFromApi(id, timer) {
timer.current = Date.now();
const triggerTime = timer.current;
fetch('path').then(() => {
if(timer.current == triggerTime) {
// process result here
// accept response and update state
}
})
}
Other ways to handle such scenarios to the cancel the previously pending API requests. IF you use Axios it provides you with cancelToken that you can use, and similarly you can cancel XMLHttpRequests too.

Prism interactivity confirmation—callback or no callback?

When using InteractionRequest with Confirmation and synchronous Raise, there are two ways of getting the result of the confirmation. The most popular way seems to be:
Confirmation confirmation = new Confirmation()
{
Title = "Confirmation",
Content = "Do you really want to do this?"
};
DeleteConfirmationRequest.Raise(confirmation, c => {
if (c.Confirmed)
{
// do something terrible
}
});
However, since I don't really care in this case whether the user cancelled the request or didn't even subscribe to the confirmation, I can do this instead:
Confirmation confirmation = new Confirmation()
{
Title = "Confirmation",
Content = "Do you really want to do this?"
};
DeleteConfirmationRequest.Raise(confirmation);
if (confirmation.Confirmed)
{
// do something terrible
}
As far as I can tell, there is no real difference between these two. Am I right, or am I missing something here?
Do you mean synchronous = a PopupWindowAction with IsModal=true for example?
In this case, the variant without the callback is fine, I guess.
Although the callback-variant is safer if implementations change, and, for example, the action's Invoke doesn't block anymore or the Confirmation is cloned internally and the callback doesn't get the same instance you passed in...

Confirm box is blocking/pausing

I have a ng-click="myFunc(aEntry)"
And then myFunc is this:
MODULE.myFunc = function(aEntry) {
aEntry.hilite = true;
if (!confirm('Are you sure?')) {
aEntry.hilite = false;
return;
}
};
However it wont update the dom to show it highlighted. The confirm box seems to be pausing it. Does anyone know a work around?
It is because confirm is a blocking function. I understand you want to have a ui change, but
aEntry.hilite = true;
is not a UI change. It is a logical change. You probably have an event handler which runs after you have called confirm. You need to guarantee that the highlighting ui operation is performed before you call the confirm. There are several ways to do it.
The most primitive way is to use setTimeout and put your confirm call inside it, using a time, which is surely longer than the time you need to wait for the ui handler to be executed.
A slightly better approach is to use setInterval until the ui change has occured.
But the best approach would be to pass the confirm with a function wrapped around it used as a callback for the ui change or to trigger the ui change event before you call confirm.

async await suitable to my case?

I've got a winform application, which has a database operation. Instead of the default UI blocking effect, I hope to display a special form like
System is processing. please wait
to tell users that the system is working. So basically I'm not looking for a real responsive UI. I still want to block the UI. I've achieved this goal with the backgroundworker component. Hookup the completed callback, then call the RunWorkerAsync in button click event handler, showdialog the processing form. Then in the completed callback, close the processing form.
I wonder if this scenario can be implemented with the new async/await mechanism. I doubt it.
What you call blocking the UI is not blocking the UI. Blocking the UI thread means to stall message processing so that the UI cannot change and react to input. The window usually is ghosted by Windows if this is detected.
You want to show a modal dialog. You can do that with BackgroundWorker or in a more modern way with async and await. For example:
void MyClickHandler(...) {
var form = new MyForm();
Task myAsyncOperation = StartOperationAsync(form);
form.ShowDialog();
await myAsyncOperation;
}
async Task StartOperationAsync(Form formToClose) {
await DoSomething();
formToClose.Close();
}
All of this code is multiplexed on the UI thread. Thread-safety is not a concern.

Resources