I am in a worker thread (I mean, thread pool task)...
I windows phone I would do:
Deployment.Current.Dispatcher.BeginInvoke(
delegate ()
{
// Do something on ui thread...
}
);
How can I do this in a Windows Store app?
I searched through msdn but came up empty...
Thanks
Here is the answer:
class ThreadUtility
{
// Warning: "Because this call is not awaited, execution of the current method
// continues before the call is completed. Consider applying the 'await'
// operator to the result of the call."
// But that's what we want here --- just to schedule it and carry on.
#pragma warning disable 4014
public static void runOnUiThread(Windows.UI.Core.DispatchedHandler del)
{
CoreWindow window = CoreWindow.GetForCurrentThread();
window.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, del);
}
#pragma warning restore 4014
}
...
ThreadUtility.runOnUiThread(
delegate ()
{
if(handler != null)
{
// Do something on ui thread...
}
}
);
Related
I'm the author of the Dart dshell package.
https://pub.dev/packages/dshell
Dshell is a library and tooling for writing dart cli scripts.
Dshell uses waitFor to hide futures from users as they serve little use in the typical cli application.
My problem is that if a future throws an unhandled exception whilst being handled by waitFor, it essentially shuts the application down.
I need to be able to capture any exception and then let the caller decided what to do with the exception.
Here is what I've tried so far. No of the catch techniques will capture the unhandled exception:
import 'dart:async';
import 'dart:cli';
void main() {
var future = throwException();
try {
future
.catchError((Object e, StackTrace st) => print('onErrr: $e'))
.whenComplete(() => print('future completed'));
print(waitFor<int>(future));
} // on AsyncError
catch (e) {
if (e.error is Exception) {
print(e.error);
} else if (e is AsyncError) {
print('Rethrowing a non DShellException ${e}');
rethrow;
} else {
print('Rethrowing a non DShellException ${e}');
rethrow;
}
} finally {
print('waitForEx finally');
}
}
Future<int> throwException() {
var complete = Completer<int>();
Future.delayed(Duration(seconds: 2), () => throw Exception());
return complete.future;
}
The dart waitFor has a line that makes me think this may not be possible:
If the Future completes normally, its result is returned. If the Future completes with an error, the error and stack trace are wrapped in an AsyncError and thrown. If a microtask or message handler run during this call results in an unhandled exception, that exception will be propagated as though the microtask or message handler was the only Dart invocation on the stack. That is, unhandled exceptions in a microtask or message handler will skip over stacks suspended in a call to waitFor.
So I'm a little confused by the difference between a 'Future completes with an error' and 'a microtask ... results in an unhandled exception'.
The Future returned by your throwException will never complete with either a value or an error. The error thrown by the Future.delayed is an unhandled async error, it is unrelated entirely to the Future that is returned from that method. The ways to get a Future that completes with an error are:
The Future.error constructor.
Using Completer.completeError on a not yet completed Completer.
Using throw in an async method.
Using throw in a callback passed to a Future constructor, or .then.
So in your example, the Future.delayed creates a Future that will complete with an error because of the throw in the callback. Nothing is listening on this Future. There is no await, no .then or .catchError chained off of it. Once a Future completes with an error, and it has no handlers for that error, it will bubble up to the surrounding error zone. See https://dart.dev/articles/archive/zones#handling-asynchronous-errors
If you want to be able to react to unhandled errors you can use runZoned - getting the details right can be tricky. Note that it's possible to have multiple unhandled async errors resulting from running some bit of code, and that the completion of a Future does not necessarily mean that there aren't other unhandled async errors that can surface later.
From Nate Bosch I've devised a possible answer:
I hadn't realised that you can add multiple onCatchError methods to a future.
In DShell I'm passed the future so I had assumed I couldn't modify it.
So I added an onCatchError to the Future.delayed and then use the completer to pass the error back up the correct stack.
So this seems to work, I'm just uncertain if I need to actually implement a zone to cast my catch net a little further?
import 'dart:async';
import 'dart:cli';
void main() {
var future = throwExceptionV3();
try {
future
.catchError((Object e, StackTrace st) => print('onErrr: $e'))
.whenComplete(() => print('future completed'));
print(waitFor<int>(future));
} // on AsyncError
catch (e) {
if (e.error is Exception) {
print(e.error);
} else if (e is AsyncError) {
print('Rethrowing a non DShellException ${e}');
rethrow;
} else {
print('Rethrowing a non DShellException ${e}');
rethrow;
}
} finally {
print('waitForEx finally');
}
}
Future<int> throwExceptionV3() {
var complete = Completer<int>();
try
{
var future = Future.delayed(Duration(seconds: 2), () => throw Exception());
future.catchError((Object e) {
print('caught 1');
complete.completeError('caught ') ;
});
}
catch (e)
{
print ('e');
}
return complete.future;
}
I suppose that the answer will be very obvious, but still it evades me. I'm new on working with observables, and now I'm facing issues assigning a value from one. I had success if I define it (this._apps) as an Observable and asking from the view to the service using subscribe (But for my taste is was way convoluted (three levels inside a map just to return another observable with the array and then another function to subscribe the previous to assign the variable and another subscription in the view to finally show the information), inefficient and on top of that I could not get it "right" again). The task is very simple. Given the class Application
export class Application {
name: string;
baseUrl: string;
deprecated: boolean;
}
And the service (just the relevant code)
private _apps: Application[] = [];
constructor(private _http: HttpClient) {
this.getAllApplications().subscribe(apps => {
console.log('Apps subscriber');
this._apps = apps;
console.log('Apps subscriber Ends ' + apps);
},
err => {
console.log(err.status); // 401
console.log(err.error.error); // undefined
console.log(JSON.parse(err.error).error); // unauthorized
});
}
private getAllApplications() {
return this._http.get<Application[]>('http://development:4300/api/v1/apps');
}
From the constructor the function which gets the information from WebAPI is triggered, and the remote call is successful, but the variable this._apps is an empty array if I try to call it from anywhere in the code. I could not determine the type of the parameter "apps" in the subscribe function, but for some reason it cannot be assigned and the best answer given is that it is a function (See my first update) in one of my tries. Currently it returns in the console "[object Object]", but apps[0] gives undefined, so it is an empty Array.
This is the console output, just starting the application:
Angular is running in the development mode. Call enableProdMode() to enable the production mode.
Refreshing apps cache calling http://development:4300/api/v1/atbc-apps
Apps subscriber
Apps subscriber Ends [object Object]
I was trying this solution among many others that I forget (to use the more modern HttpClient instead the Http I used before), so what I'm doing wrong?
Update 1
I changed the constructor to this:
constructor(private _http: HttpClient) {
this.getAllApplications().subscribe(apps => {
console.log('apps length ' + apps.length);
this._apps = apps; // Remember private _apps: Application[] = [];
console.log('Apps subscriber Ends ' + apps.toString);
},
err => {
console.log(err.status); // 401
console.log(err.error.error); // undefined
console.log(JSON.parse(err.error).error); // unauthorized
});
}
and the declaration of the function called into this:
private getAllApplications(): Observable<Application[]> {
// the exactly the same as before
}
And now I got from the console this:
apps length undefined
Apps subscriber Ends
function () {
if (this instanceof Promise) {
return PROMISE_OBJECT_TO_STRING;
}
return originalObjectToString.apply(this, arguments);
}
That is the function I was talking about. Any ideas about why even though there is no errors (nor at compile time, neither at runtime), the returning object is not a real Application array?
Change this line:
private _apps: Application[] = [];
to:
_apps: Application[] = [];
Which will default to making it public. Then this line will see it:
this._apps = apps;
At the end I suppose is a mindset to work with Observables, and I tried to build a kind of cache, so the only way I could do it (let me know if there is a better way) was using the view to fill-out the cache. I could not do it from the service itself because the calling the function from the view is synchronous and to fill out the array is async. So I had to create a public setApplicationCache procedure which is filled out after calling the service from the view, it call the setApplicationCache( Application[] ) function and the rest works because it takes just the cache to do filtering and other operations or use it from other pages w/o calling the database again and again.
This is the code from the first view called (main page)
ngOnInit() {
this._myService.getAllApplications().subscribe(arrObjApps => {
this._myService.setApplicationsCache(arrObjApps)
this.listApps = this._myService.getApplications(true);
});
And the service has this functions:
private _apps: Application[] = [];
getAllApplications(): Observable<Application[]> {
return this._http.get('http://development:4300/api/v1/atbc-apps').pipe(
map( (response: Response) => {
let results = response.json().data.map( app => {
return new Application(app.name, app.baseUrl, app.deprecated);
});
return results;
})
);
}
getApplication(appName: string): Application {
return this._apps.find(app => app.name == appName);
}
getApplications(onlyActives: boolean): Application[] {
if (onlyActives) {
return this._apps.filter(app => app.deprecated == false);
} else {
return this._apps;
}
}
And as I stated the solution should be obvious. Just again the async mindset required to work with observables.
So I have a UI thread. Person clicks something because they feel like it. So click triggers some function calls. One of the underlying function calls uses CDROM driver that reads dirty discs by trying a couple of times and making that crazy thumping.
So I want a responsive UI and i put await on my function call. So when person clicks, function relinquishes control to UI thread. Function tries to read the CDROM, but it is really dirty so it throws an exception to its caller. That caller counts the number of retries and keeps trying three times.
So, if this is all await, where do I keep the count?
If I keep the count in a lower level and that level relinquishes with await, it can't keep retrying until three attempts because IT IS RELINQUISHED.
But if I don't relinquish, I can't maintain a responsive UI.
Do I keep the count in the Task object? And exactly which thread/await level can be responsible for checking the retry count?
You can put your retry logic wherever is most appropriate. await works perfectly well with try:
public async Task PerformOperationAsync(int retries)
{
while (retries != 0)
{
try
{
await PerformSingleOperationAsync();
return;
}
catch (Exception ex)
{
Log(ex);
--retries;
}
}
}
The code above will ignore failures if it runs out of retries. You can also throw the last error:
public async Task PerformOperationAsync(int retries)
{
while (true)
{
try
{
await PerformSingleOperationAsync();
return;
}
catch (Exception ex)
{
Log(ex);
if (--retries == 0)
throw;
}
}
}
Throwing the first error or a collection of all the errors is left as an exercise for the reader. ;)
Anyone knows what the status of Web Worker support in NodeJS is? I found a two year old implementation, node-webworkers, but it didn't run with the current build of NodeJS.
Now there is https://github.com/audreyt/node-webworker-threads which appears to be actively maintained.
Worker Threads reached stable status in 12 LTS. Usage example
const {
Worker, isMainThread, parentPort, workerData
} = require('worker_threads');
if (isMainThread) {
module.exports = function parseJSAsync(script) {
return new Promise((resolve, reject) => {
const worker = new Worker(__filename, {
workerData: script
});
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0)
reject(new Error(`Worker stopped with exit code ${code}`));
});
});
};
} else {
const { parse } = require('some-js-parsing-library');
const script = workerData;
parentPort.postMessage(parse(script));
}
You can use the child processes, they solve similar problems.
You can look at the specifics of the HTML5 WebWorker source.
With a little care, you can 'redress' the WebWorker to fit as a Node.js worker, by adding a prelude that may look something like this:
const { parentPort } = require('worker_threads')
global.postMessage = function(msg){
parentPort.postMessage(msg)
}
var handler
global.addEventListener = function(kind, callback){
handler = callback
}
parentPort.on('message', msg => {
handler(msg)
})
The specific HTML5 worker added a message event handler using addEventListener, so I registered such a function in global and saved the handler. I also had to supply a postMessage implementation. Finally I registered a Node.js message handler that invokes the HTML5 handler.
Everything works perfectly. No need for any special dependency, just looking at the HTML5 worker code and identify the points where it deals with messages.
My applet connects to FMS4.5 using RTMFP. I open one NetConnection and stream video from the server to the applet using a NetStream. When i want to execute a function on either the applet or the server i use a NetConnection.call();
My question is does AS3 do anything internally to make sure the call over UDP happens or is there a risk of UDP loss and the function never happening when it is called?
Assuming there might be times the UDP traffic is lost i made a responder retry onStatus. Does this code look like it would actually do the job or is it overkill?
// This is code on FMS to call a function in the applet.
var networkRetryMax = 30;
if (something == true) doSomethingInApplet(client, 0);
function doSomethingInApplet (client, retryCount) {
if (retryCount < networkRetryMax) {
retryCount++;
client.call("funcNameInApplet", new doSomethingInAppletResponder(client, retryCount), "foobar");
}
return;
}
function doSomethingInAppletResponder (client, retryCount) {
this.onResult = function() {...}
this.onStatus = function() {doSomethingInApplet(client, retryCount);}
return;
}
And...
// This is code in the applet.
// I return true to give it something to onResult or onStatus.
public static function funcNameInApplet(result:String):Boolean {
trace("Result: " + result);
return true;
}
So would this ensure the function is called over UDP / RTMFP?
Or is .call() reliability handled internally and this is unnecessary?