-
14 Sep 2007 8:44 AM #21
You mean 'synchronous' request support, right?
As I posted previously, this is availabe for Ext here."be dom-ready..."
Doug Hendricks
Maintaining ux: ManagedIFrame, MIF2 (FAQ, Wiki), ux.Media/Flash, AudioEvents, ux.Chart[Fusion,OFC,amChart], ext-basex.js/$JIT, Documentation Site.
Got Sencha licensing questions? Find out more here.
-
14 Sep 2007 8:56 AM #22
I am a bit disappointed in the Ext folks here. Most of the time calls should be asynchronous, but to purposefully design away the ability to make synchronous calls is naive at best. There are times and situations where asynchronous just will not do, many of which have already been highlighted here.
Hendricd... Your code is a little difficult to understand. It doesn't look like it was purpose built for Sync requests.
From the way I see it, it appears that one would have to patch both the Connection.js and all the bindings in order to achieve synchronous requests.
Perhaps you can explain your methodology.
-
14 Sep 2007 11:43 AM #23
Sure. I'll give this a shot...
Sure. I'll give this a shot...
To review: XMLHttpRequest (herein XHR) behaviour:Perhaps you can explain your methodology.- A synchronous call blocks the browser's current execution thread until complete.
- There are no timeouts.
[All dry stuff here, but:]
The Ext.data.Connection class was designed with an 'event-model' in mind. That 'event-model' is inherent in every Ext component/widget. That event-model implies asynchonous XHR support for interaction with data sources, because without support for a 'timeout', these components/widgets would 'appear' to lock up during a long-running server response. From a UI perspective that is King! Kudos: Jack !
Ext.lib.Ajax, on the other hand, is the work-horse of the entire AJAX framework. I targeted these enhancements to this area because:- The 'event-driven' expectations of it's consumers (Ext components/widgets/dataStores and data.Connection) must be preserved.
- The success of an Ajax request throughout the framework is predicated on evaluation of HTTP status codes at the lib.Ajax level. XHR returns a status of (0) for local file systems. Ext, out-of-the-box, considers that a failure. Wanted that/need that to change

- For async calls, Ext uses a poll-timer to monitor the progress of the call. If it's taking to long, the timeout event trickles up the chain to event subscribers. data.Connection (an abstraction layer) could care less about these timers, as its event model simply responds to the few events that lib.Ajax generates. For synchronous support, there is no need for such timers because they won't run because the browser context is blocked. You finally get a response when the browser gives up. Again, IMO data.Connection was/is not the proper place for these mods.
- IE7 (as you may know) introduced it's own native (vs ActiveX) XHR API, and it's own set of problems (not addressing all those here
). The override also gives you a choice of which implementation to use. - The XHR open, send methods are wrapped (and raise appropriate exceptions) when the browser barks about security and other issues. The response object status is enriched to indicate what the problem was -- didn't have that before.
- It also adds UserId and password auth support for XHR.
So, yes, it may appear that the structure of localXHR.js (and the naming convention is likely ambiguous) was based on 'after-thought'. I assure all who use it -- it was not. It was re-factored to account for the issues mentioned earlier and more.
That said, two no, three design consideration stands out from all others:
1) Preserve Ext components/widgets thirst for events, whether async or sync. That's why the event model still works regardless.
2) data.Connection is not part of the Core, it's a package (you'll likely want to load later
).
3) data.Connection gets sub-classed a lot. lib.Ajax is core, so all components benefit.
The last example on this thread uses the event-based approach (even though the requests are made synchronously) to demonstrate that you can stick with UI-events in your App even though you are blocking the browser every time you do so.
Keep in mind -- for a synchronous request, the response object is also returned immediately by the call to lib.Ajax.request() upon completion (which means it's also returned to data.Connection if you want to deal with it on that level).
So, for all you synchronous-js-loader-wannebees, this is now possible:
Clear asCode:<head> <link rel="stylesheet" type="text/css" href="src/resources/css/ext-all.css" /> <script type="text/javascript" id="ext-base" src="src/ext-base.js"></script> <script type="text/javascript" src="src/localXHR.js"></script> <script type="text/javascript"> Ext.ux.ModuleManager = function(config){ Ext.ux.ModuleManager.superclass.constructor.call(this,config); this.asynchronous = false; Ext.apply(this,config||{},{modulePath:function(){ //based on current page var d= location.href.indexOf('\/') != -1 ? '\/':'\\'; var u=location.href.split(d); u.pop(); //this page return u.join(d) + d; }()} ); this.modules = {}; this.addEvents({ /** * @event loadexception * Fires when any exception is raised * returning false prevents any subsequent pending module load requests * @param {Ext.ux.ModuleManager} this * @param {String} module -- the module name * @param {Object} error -- An error object containing: httpStatus, httpStatusText, error object */ "loadexception" : true, /** * @event alreadyloaded * Fires when the ModuleManager determines that the requested module has already been loaded * @param {Ext.ux.ModuleManager} this * @param {String} module -- the module name */ "alreadyloaded" : true, /** * @event load * Fires when the retrieved content has been successfully evaled into the current context. * @param {Ext.ux.ModuleManager} this * @param {String} module -- the module name */ "load" : true, /** * @event beforeload * Fires when the request has successfully completed and just prior to eval * returning false prevents the content (of this module) from being loaded (eval'ed) * @param {Ext.ux.ModuleManager} this * @param {String} module -- the module name * @param {Object} response - the Ajax response object */ "beforeload" : true }); }; Ext.extend(Ext.ux.ModuleManager,Ext.util.Observable,{ loaded:function(name){ return this.modules[name]===true; } ,load:function(){ var result = true ,keepItUp = true ,StopIter = new Error("StopIteration") ,reqOptions = { method:this.method||'GET' ,async:this.asynchronous ,url:null ,success:function(response,options){ try{ if(this.fireEvent('beforeload', this, options.module, response) !== false){ this.globalEval( response.responseText ); this.modules[options.module]=true; this.fireEvent('load', this, options.module); } }catch(ex) { keepItUp = this.fireEvent('loadexception', this, options.module,{ error :ex ,httpStatus :response.status ,httpStatusText:response.statusText }); result = false; } } ,failure:function(response,options){ keepItUp = this.fireEvent('loadexception', this, options.module,{ error :response.stat.error ,httpStatus :response.status ,httpStatusText:response.statusText }); result = false; } ,scope:this }; /* Iterate the desired modules in there implied dependency order */ try{ var mm = this; Ext.each(arguments , function(module){ var fullModule = module.indexOf('.')>-1?module:module + '.js'; var opt=Ext.apply({},{url:mm.modulePath + fullModule ,module:module},reqOptions); if(!mm.loaded(module)){ Ext.Ajax.request(opt); } else { keepItUp = mm.fireEvent('alreadyloaded', mm, module); } if(keepItUp===false)throw StopIter; }); } catch(ex){ if (ex != StopIter)throw ex; } return result; } ,globalEval: function( data , scope ) { scope || (scope = window); if ( scope.execScript ) scope.execScript( data ); else if ( Ext.isSafari ) // safari doesn't provide a synchronous global eval scope.setTimeout( data, 0 ); else eval.call( scope, data ); } }); Ext.ModuleManager=new Ext.ux.ModuleManager({}); Ext.ModuleManager.modulePath += 'packages/'; Ext.ModuleManager.on({ //setup a default beforeload handler to verify Content-Type header 'beforeload':function(manager, module, response){ // response.responseText may be analyzed/modified at this point. return response.stat.isLocal || (response.getResponseHeader['Content-Type']||'').indexOf('javascript')!=-1; //return false to prevent the script from being evaled. } ,scope:Ext.ModuleManager }); //Now call your global loader anything you want: Ext.require = Ext.ModuleManager.load.createDelegate(Ext.ModuleManager); if(!Ext.require('core','dragdrop','menu','data','grid','ux/widget','ovr/custom.js')){panic()}; </script> </head>
?
Footnote: There are a few Asynch design patterns that would accomplish the same thing, but that's another story -- and much debate.
I'll bow out on that one though.
Last edited by hendricd; 16 Sep 2007 at 4:34 AM. Reason: Replaced Example with ux version that actually works!
"be dom-ready..."
Doug Hendricks
Maintaining ux: ManagedIFrame, MIF2 (FAQ, Wiki), ux.Media/Flash, AudioEvents, ux.Chart[Fusion,OFC,amChart], ext-basex.js/$JIT, Documentation Site.
Got Sencha licensing questions? Find out more here.
-
15 Sep 2007 11:51 AM #24
[Update]
The previous post now includes a fully functional js module loader.
I'll be ux.packaging it up and expanding docs on it soon.
Enjoy."be dom-ready..."
Doug Hendricks
Maintaining ux: ManagedIFrame, MIF2 (FAQ, Wiki), ux.Media/Flash, AudioEvents, ux.Chart[Fusion,OFC,amChart], ext-basex.js/$JIT, Documentation Site.
Got Sencha licensing questions? Find out more here.
-
1 Oct 2007 7:09 AM #25
Just back from AJAX-World conf', it was a great event
. Anyway, as a matter of fact when Jesse James Garrett came up with the term "AJAX" he did not mean for it to be an acronym for sure... So, from historical point of view AJAX was Ajax, just, not "Asynchronous blablabla"
Cheers.Necessity is the Mother of invention
-
1 Oct 2007 7:29 AM #26
Here's his original essay:
http://www.adaptivepath.com/ideas/es...ves/000385.php
Defining Ajax... "asynchronous data retrieval using XMLHttpRequest;"
If you read the article, he specifically contrasts the classic synchronous model with the new Ajax asynchronous model.

-
2 Oct 2007 7:16 AM #27
Hi Brian,
I feel you jumped too quickly on this, I was not arguing about the asynchronous side of the story but rather the fact Ajax was originally not an acronym but simply a name for a set of technologies coming together.. I am an old fox who likes to call things in the right way
Cheers.Necessity is the Mother of invention
-
2 Oct 2007 7:27 AM #28
I was just playing devil's advocate. The context of this thread is a debate on whether or not synchronous calls are useful in Ajax, so I read your post in that light.
-
3 Oct 2007 12:13 PM #29
In my humble opinion sync. javascript calls are bad for one reason: they block the UI thread, and give the user the impression the browser/app is frozen. This is bad UI design.
-
3 Oct 2007 12:48 PM #30
95% of the time you would be correct; but a framework as well designed as Ext should provide some form of synchronous access for the other 5%. It can be undocumented, a bit out of the way, anything to keep people who don't know any better from using it. However, it should exist.






Reply With Quote