How to Profile (Debug) ExtJS EventPipe / Events - extjs

I am working on a relatively large ExtJS MVC application with around >40 Controllers, >100 Stores, >100 Models and so on. I don't follow the possible MVC way strict so I implemented a lazy controller initialization which initialize the controller first when it is required and so the stores. I also don't register any view within any controller, but that simply cause I don't need to.
Now it comes that forms (opened within a Ext.window.Window) take around 1-2 second until they shown up while the same form within a rather small project pops up immediately.
So the form (layout) can not be the problem here what brought me to the events. But I don't really know how would be the best way or is there already a good tutorial how to do this. I guess it would be nice to profile this, to see how long the whole pipe takes (not only the EventPipe itself).
Event structure:
Most of the events get registered via control() of the responsible controller. All other events are at most registered with { single: true }. The windows get closed and reinstantiated when reused.

I'm afraid but ExtJS doesn't provide any event profiling. It use custom event system.
Here is how I see the solution of this issue.
There are Ext.util.Event class that provides functionality to dispatching and handling any event used in the framework and Ext.app.EventBus that provide single point to dispatch all framework events (fireEvent is just wrapper for Ext.app.EventBus.dispatch method).
Classes are private so I recommend to see its source code.
You can override these classes to see how much it takes from calling Ext.app.EventBus.dispatch method and calling event listener within Ext.util.Event.fire method smth like that (EventProfiler is supposed to be your own class)
Ext.app.EventBus
dispatch: function (/* event name or Ext.util.Event */event, /* Target class */ target, args) {
//start timing
var start = new Date();
/* ... */
for (i = 0, ln = events.length; i < ln; i++) {
event = events[i];
// Fire the event!
if (event.fire.apply(event, Array.prototype.slice.call(args, 1)) === false) {
return false;
}
// start event profiling
// here we are sure that event is dispatched and it's instance of Ext.util.Event
EventProfiler.startProfile(event, /* time passed from dispath method started */new Date() - start);
}
/* rest of dispatch method call */
}
Ext.util.Event
fire: function () {
/* ... */
if (listener.o) {
args.push(listener.o);
}
EventProfiler.endProfile(this);
if (listener && listener.fireFn.apply(listener.scope || me.observable, args) === false) {
return (me.firing = false);
}
/* ... */
}

Related

Creating a new UI thread while calling methods on the original thread

I am in a similar situation as this poster (What's the best way to create a new UI thread and call back methods on the original thread?)
I have an API object which I would like to perform lengthy calculations on, however any properties or methods of this object must be accessed on the current thread (which is the UI thread) or else I get "Accessing disposed TPS.NET DataObject" exceptions
Is there an elegant way of accomplishing this using F# async workflows or will I be stuck managing thread dispatchers as in his solution.
For reference, here is his solution to the issue:
public class Plugin
{
public void Run(Context context)
{
// Get the application's UI thread dispatcher
var dispatcher = Dispatcher.CurrentDispatcher;
// Create a dispatcher frame to push later
var frame = new DispatcherFrame();
// Create a new UI thread (using an StaTaskScheduler)
Task.Factory.StartNew(async () =>
{
var window = new MyWindow();
// The Click event handler now uses the original
// thread's dispatcher to run the slow method
window.MyButton.Click += async (o, e) =>
await dispatcher.InvokeAsync(() => context.SlowMethod());
window.ShowDialog();
// When the window is closed, end the dispatcher frame
frame.Continue = false;
}, CancellationToken.None, TaskCreationOptions.None, new StaTaskScheduler(1));
// Prevent exiting this Run method until the frame is done
Dispatcher.PushFrame(frame);
}
}
Without know the exact details I would suggest having the Click handler on the main thread and do the following:
Copy any data needed off the UI into an F# record and passes this into an async workflow
Return immediately after putting the UI into a 'loading' state
The following code is untested but should put you on the right track:
//Get the context of the UI
let context = System.Threading.SynchronizationContext.Current
//Gather any needed data from the UI into immutable F# records
//Put the UI into a 'loading' state
async {
// Do work on a different thread
do! Async.Sleep 1000
let x = 1
// Switching back to the UI
do! Async.SwitchToContext context
//Update UI
return ()
}
|> Async.Start
This link should also provide some useful information http://tomasp.net/blog/async-non-blocking-gui.aspx/
EDIT:
If you need to go back and forth between the UI thread and a background thread to gather additional information in the async workflow you can make alternating calls between do! Async.SwitchToThreadPool() and do! Async.SwitchToContext context

How to ensure wcf service client finishs his works in silverlight?

I use wcf service client to submit changes of data for a silverlight project. The correlative codes like this:
public class DispatcherCollection : UpdatableCollection<DocumentDispatcher>
{
public override void SubmitChanges()
{
DocumentServiceClient client = new DocumentServiceClient();
client.NewDocumentCompleted += (s, e) =>
{
// (s as DocumentServiceClient).CloseAsync();
// do something
};
client.UpdateColumnCompleted += (s, e) =>
{
// (s as DocumentServiceClient).CloseAsync();
// do something
};
client.RemoveDocumentCompleted += (s, e) =>
{
// (s as DocumentServiceClient).CloseAsync();
// do something
};
foreach (DocumentDispatcher d in this)
{
if (d.IsNew)
{
// d=>object[] data
client.NewDocumentAsync(data);
d.IsNew=false;
}
else
{
foreach (string propertyName in d.modifiedProperties)
{
client.UpdateColumnAsync(d.ID, GetPropertyValue(propertyName));
}
dd.ClearModifications();
}
}
foreach (DocumentDispatcher dd in removedItems)
{
client.RemoveDocumentAsync(dd.ID);
}
removedItems.Clear();
}
}
Class UpdatableCollection derives from ObserableCollection, and I implemtent logics in class DocumentDispatcher and UpdatableCollection to buffer the changes of data such as new created, property modified and removed. I use SubmitChanges method to submit all changes to server.
Now I am stuck:
1. I am at a loss when to close the client after a bunlde fo async calls. I don't know which callback is the last one.
2. What will happen when a user closes the IE immediately right after clicking the save button (it seems to be done because it runs async but in fact the updating threads are industriously running.)?
You can keep a counter or use an isbusy function to monitor the callbacks from your Async calls - to make sure they all finished.
If the user fires off a request to the WCF service, the WCF service will complete but there will be no call back - as the application will be closed.
I think that there is no wait handle for silverlight asynchornized call brings inconvenience. Here is my experence. I want to check and submit modifications of data which are not expicitly submitted when browser is closing. I have implemented codes in App_Exit like this:
private void Application_Exit(object sender, EventArgs e)
{
Document doc = EDPViewModel.CurrentViewModel.Document;
if (doc != null) new ServiceClient().SubmitChangesAsync(doc);
}
provided that in the SubmitChangesAsync method, not submitted modifications of doc are found out and submitted. Therefore, because of the asynchronized running features, while the service invoking is being sent, the application is yet immediately closed. And that will dispose related resouces of the application, including Service Invoking Tasks. So the codes above work not. I hope so eagerly that somewhere exists a mechanism, which can export a wait handle from silverlight asynchronized call, so that I can update the above codes whith this:
private void Application_Exit(object sender, EventArgs e)
{
Document doc = EDPViewModel.CurrentViewModel.Document;
if (doc != null)
{
Task t = new TaskFactory().StartNew(() => new ServiceClient().SubmitChangesAsync(doc));
t.Wait();
}
}
With wait operation I can really be sure that all modifications are really definitely submitted. So is there any similar pattern that can be used in silverlight?
It's for me a good news, as you put it, that calls could work like the mode "requesting and forgetting". So I needn' to worry too much about data losing during submitting.
To ensure all service calls are sent out before application is closed, I think, counter is a simple and effient idea. I will try to implement it in my project.
Thank you for your help!

Update DataContext from background thread

I fetch data for a wpf window in a backgroundthread like this [framework 4.0 with async/await]:
async void refresh()
{
// returns object of type Instances
DataContext = await Task.Factory.StartNew(() => serviceagent.GetInstances());
var instances = DataContext as Instances;
await Task.Factory.StartNew(() => serviceagent.GetGroups(instances));
// * problem here * instances.Groups is filled but UI not updated
}
When I include the actions of GetGroups in GetInstances the UI shows the groups.
When I update in a seperate action the DataContext includes the groups correclty but the UI doesn't show them.
In the GetGroups() method I inlcuded NotifyCollectionChangedAction.Reset for the ObservableCollection of groups and this doesn't help.
Extra strange is that I call NotifyCollectionChangedAction.Reset on the list only once, but is executed three times, while the list has ten items?!
I can solve the issue by writing:
DataContext = await Task.Factory.StartNew(() => serviceagent.GetGroups(instances));
But is this the regular way for updating DataContxt and UI via a backgound process?
Actually I only want to update the existing DataContext without setting it again?
EDIT: serviceagent.GetGroups(instances) in more detail:
public void GetGroups(Instances instances)
{
// web call
instances.Admin = service.GetAdmin();
// set groups for binding in UI
instances.Groups = new ViewModelCollection<Groep>(instances.Admin.Groups);
// this code has no effect
instances.Groups.RaiseCollectionChanged();
}
Here ViewModelCollection<T> inherits from ObservableCollection<T> and I added the method:
public void RaiseCollectionChanged()
{
var handler = CollectionChanged;
if (handler != null)
{
Trace.WriteLine("collection changed");
var e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
handler(this, e);
}
}
There's a few points that stand out in the async portion of your code:
I explain why we should avoid async void in my MSDN article. In summary, void is an unnatural return type for async methods, so it has some quirks, particularly around exception handling.
We should prefer TaskEx.Run over StartNew for asynchronous tasks, as I explain on my blog.
While not exactly required, it's a good idea to follow the guidelines in the Task-based Asynchronous Pattern; following those naming conventions (etc) will help other developers to maintain the code.
Based on these, I also recommend my intro to async blog post.
On to the actual problem...
Updating data-bound code from background threads is always tricky. I recommend that you treat your ViewModel data as though it were part of the UI (it is a "logical UI", so to speak). So it's fine to retrieve data on a background thread, but updating the actual VM values should be done on the UI thread.
These changes make your code look more like this:
async Task RefreshAsync()
{
var instances = await TaskEx.Run(() => serviceagent.GetInstances());
DataContext = instances;
var groupResults = await TaskEx.Run(() => serviceagent.GetGroups(instances));
instances.Admin = groupResults.Admin;
instances.Groups = new ObservableCollection<Group>(groupResults.Groups);
}
public GroupsResult GetGroups(Instances instances)
{
return new GroupsResult
{
Admin = service.GetAdmin(),
Groups = Admin.Groups.ToArray(),
};
}
The next thing you need to check is whether Instances implements INotifyPropertyChanged. You don't need to raise a Reset collection changed event when setting Groups; since Groups is a property on Instances, it's the responsibility of Instances to raise INotifyPropertyChanged.PropertyChanged.
Alternatively, you could just set DataContext last:
async Task RefreshAsync()
{
var instances = await TaskEx.Run(() => serviceagent.GetInstances());
var groupResults = await TaskEx.Run(() => serviceagent.GetGroups(instances));
instances.Admin = groupResults.Admin;
instances.Groups = new ObservableCollection<Group>(groupResults.Admin.Groups);
DataContext = instances;
}
Seems there's a bit of confusion on what DataContext is. DataContext is not some special object that you have to update. It's a reference to the object or objects that you want to bind to your UI. Whenever you make changest to these objects, the UI get's notified (if you implement the proper interfaces).
So, unless you explicitly change the DataContext, your UI can't guess that now you want to show a different set of objects.
In fact, in your code, there is no reason to set the DataContext twice. Just set it with the final set of objects you want to display. In fact, since you work on the same data, there is no reason to use two tasks:
async Task refresh()
{
// returns object of type Instances
DataContext=await Task.Factory.StartNew(() => {
var instances = serviceagent.GetInstances();
return serviceagent.GetGroups(instances);
});
}
NOTE:
You should neer use the async void signature. It is used only for fire-and-forget event handlers, where you don't care whether they succeed or fail. The reason is that an async void method can't be awaited so no-one can know whether it succeeded or not.
I discovered that RaiseCollectionChanged has no influence on the property Groups where the DataContext is bound to. I simply have to notify: instances.RaisePropertyChanged("Groups");.

How to invoke on the UI thread of a WinForm Component?

I'm coding a WinForm component where I start a Task to do the actual processing and trap the exception on a continuation. From there I want to show the exception message on a UI element.
Task myTask = Task.Factory.StartNew (() => SomeMethod(someArgs));
myTask.ContinueWith (antecedant => uiTextBox.Text = antecedant.Exception.Message,
TaskContinuationOptions.OnlyOnFaulted);
Now I get a cross-thread exception because the task is trying to update a UI element from a, obviously, non UI thread.
However, there is no Invoke or BeginInvoke defined in the Component class.
How to proceed from here?
UPDATE
Also, please note that Invoke/BeginInvoke/InvokeRequired are not available from my Component-derived class since Component doesn't provide them.
You could just add a property to your component, allows the client to set a form reference that you can use to call its BeginInvoke() method.
That can be done automatically as well, preferable so nobody can forget. It requires a bit of design time magic that's fairly impenetrable. I didn't come up with this by myself, I got it from the ErrorProvider component. Trusted source and all that. Paste this into your component source code:
using System.Windows.Forms;
using System.ComponentModel.Design;
...
[Browsable(false)]
public Form ParentForm { get; set; }
public override ISite Site {
set {
// Runs at design time, ensures designer initializes ParentForm
base.Site = value;
if (value != null) {
IDesignerHost service = value.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (service != null) this.ParentForm = service.RootComponent as Form;
}
}
}
The designer automatically sets the ParentForm property when the user drops your component on a form. Use ParentForm.BeginInvoke().
You can use delegates to do this.
delegate void UpdateStatusDelegate (string value);
void UpdateStatus(string value)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new UpdateStatusDelegate(UpdateStatus), new object[]{value});
return;
}
// Must be on the UI thread if we've got this far
statusIndicator.Text = value;
}

Silverlight Async Design Pattern Issue

I'm in the middle of a Silverlight application and I have a function which needs to call a webservice and using the result complete the rest of the function.
My issue is that I would have normally done a synchronous web service call got the result and using that carried on with the function. As Silverlight doesn't support synchronous web service calls without additional custom classes to mimic it, I figure it would be best to go with the flow of async rather than fight it. So my question relates around whats the best design pattern for working with async calls in program flow.
In the following example I want to use the myFunction TypeId parameter depending on the return value of the web service call. But I don't want to call the web service until this function is called. How can I alter my code design to allow for the async call?
string _myPath;
bool myFunction(Guid TypeId)
{
WS_WebService1.WS_WebService1SoapClient proxy = new WS_WebService1.WS_WebService1SoapClient();
proxy.GetPathByTypeIdCompleted += new System.EventHandler<WS_WebService1.GetPathByTypeIdCompleted>(proxy_GetPathByTypeIdCompleted);
proxy.GetPathByTypeIdAsync(TypeId);
// Get return value
if (myPath == "\\Server1")
{
//Use the TypeId parameter in here
}
}
void proxy_GetPathByTypeIdCompleted(object sender, WS_WebService1.GetPathByTypeIdCompletedEventArgs e)
{
string server = e.Result.Server;
myPath = '\\' + server;
}
Thanks in advance,
Mike
The best would be to use Reactive Extensions. Then (assuming you'd create an extension method IObservable<string> GetPathByTypeId(string typeId) on WS_WebService1SoapClient you can do this:
proxy
.GetPathByTypeId(TypeId)
.Subscribe(server =>
{
//Here you can do stuff with the returned value
});
As close to having synchronous call as it gets :)
Given the asynch nature of Silverlight you cannot return values from myFunction. Instead you can pass an Action which is executed once the service call is complete. See the example code below. I am not sure if it is considered best practice, but I use this "pattern" a lot and it has always worked fine for me.
EDIT
Updated the code below to include multiple arguments in the callback action.
void DoSomething(Guid TypeId, Action<int, bool> Callback)
{
WS_WebService1.WS_WebService1SoapClient proxy = new WS_WebService1.WS_WebService1SoapClient();
proxy.GetPathByTypeIdCompleted += (s, e) =>
{
string server = e.Result.Server;
myPath = '\\' + server;
//
if (myPath == "\\Server1")
{
Callback(888, true);
}
else
{
Callback(999, false);
}
};
proxy.GetPathByTypeIdAsync(TypeId);
}
void CallDoSomething()
{
DoSomething(Guid.NewGuid(), (returnValue1, returnValue2) =>
{
//Here you can do stuff with the returned value(s)
});
}
Put the processing of the GetPathByTypeId result into the GetPathByTypeIdCompleted callback. Assign mypath there. Make mypath a property and implement the INotifyPropertyChanged interface to notify dependents of Mypath that Mypath has changed.
Observer depends on mypath
Observer sets a notification event for mypath
Get Mypath by asynchronous invocation of GetPathByTypeId
Mypath is set, invokes notifiaction of Observer
Observer works with Mypath

Resources