Hi,
in our application, the user sees a dashboard right after logging in. Depending on the configuration of this dashboard, load and render times can get quite long. So we tried to wrap slow components into a Decoration that uses load() to postponbe the loading of their content. The render code in our decoration looks like this: replaced ifTrue: [div with: [self renderNextOn: html]] ifFalse: [ html document addLoadScript: ( (html jQuery: self idSelector) load html: [:r | replaced := true. self renderNextOn: html]). div with: [ html image src: someSpinnerImage html space; text: self message]] Thus, we hoped, the page would display very quickly, and be responsive before all the widgets are loaded. So far, we've reached one of the two goals: the page now loads quickly and the widgets use ajax to load their contents later. Another nice side effect is that if you go back to the start page, all widgets are loaded already. The other goal, however, is not met: If you log in and immediately click on one of the menu items, the browser won't react to your click before all widgets have finished loading. So it seems like jQuery's load is blocking. We've tried in Chrome and Firefox, and both expose this behavior. Does anybody know how to not only cheat on the load times of our dashboard but also enable the browser to react on clicks before all widgets have loaded their contents? Any hint is appreciated, Joachim |
As an illustration of what we want to do, you can look at the Wordpress
Admin panel: teh traffic statistics come up with a "Loadind" Spinner, and while the statistics are being loaded from the Server, you can already click on links and immediately go to, say, the editor for new posts. In our Seaside app, the browser will not react immediately but wait until all calls to load() have finished... Joachim -- ----------------------------------------------------------------------- Objektfabrik Joachim Tuchel mailto:[hidden email] Fliederweg 1 http://www.objektfabrik.de D-71640 Ludwigsburg http://joachimtuchel.wordpress.com Telefon: +49 7141 56 10 86 0 Fax: +49 7141 56 10 86 1 _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by jtuchel
Hi Joachim,
jQuery load is an ajax request and should thus not be blocking any browser action. What kind of interaction are you expecting from the ‘click’ to which the browser is not responder? A page request, an ajax request, the execution of a javascript program, ... ? Johan > On 19 Nov 2015, at 09:59, jtuchel <[hidden email]> wrote: > > Hi, > > in our application, the user sees a dashboard right after logging in. > Depending on the configuration of this dashboard, load and render times can > get quite long. > > So we tried to wrap slow components into a Decoration that uses load() to > postponbe the loading of their content. The render code in our decoration > looks like this: > > replaced > ifTrue: [div with: [self renderNextOn: html]] > ifFalse: [ > html document addLoadScript: ( > (html jQuery: self idSelector) load html: [:r | > replaced := true. > self renderNextOn: html]). > div with: [ > html image src: someSpinnerImage > html space; text: self message]] > > > > Thus, we hoped, the page would display very quickly, and be responsive > before all the widgets are loaded. > > So far, we've reached one of the two goals: the page now loads quickly and > the widgets use ajax to load their contents later. Another nice side effect > is that if you go back to the start page, all widgets are loaded already. > > The other goal, however, is not met: If you log in and immediately click on > one of the menu items, the browser won't react to your click before all > widgets have finished loading. So it seems like jQuery's load is blocking. > > We've tried in Chrome and Firefox, and both expose this behavior. > Does anybody know how to not only cheat on the load times of our dashboard > but also enable the browser to react on clicks before all widgets have > loaded their contents? > > Any hint is appreciated, > > Joachim > > > > -- > View this message in context: http://forum.world.st/Non-blocking-jQuery-load-tp4861881.html > Sent from the Seaside General mailing list archive at Nabble.com. > _______________________________________________ > seaside mailing list > [hidden email] > http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Hi Johan,
Am 19.11.15 um 22:17 schrieb Johan Brichau-2 [via Smalltalk]: Hi Joachim, Yes, that's what I thought as well... On our Dashboard we have the main navigation menu which consists of anchors with normal callback blocks. After I had sent my last mail, I saw that both ajax requests take about the same time to finish (4022 and 4096 ms on a slow development machine), so I thought maybe this all is just a coincidence. So here is what I've tried then: I added a (Delay forSeconds: 5) wait to one of our dashboard widget's business code. What happens is this: The widgets all immediately start an ajax request, and the one without the Delay gets rendered after the usual 4 seconds. The other one renders a bit more than 5 seconds later. So far, so unsurprising. BUT: If I click on one of the main navigation links (which should be totally unrelated to the Components that issue the ajax call), the callback is not called before the longer runnin Ajax request is finished. The Re-rendering of the Component in the Browser is not performed, however (at least I can't see it). So the first observation seems to tell me the "load html:" calls are not blocking. The second, however, seems to indicate that they block. Or (shiver) there is something strange going on on the server side (VA Smalltalk) that keeps the server from handling the "normal" request before the ajax requests are finished. I need to test with a bit more logging to find out... Thanks for listening, Joachim
-- ----------------------------------------------------------------------- Objektfabrik Joachim Tuchel [hidden email] Fliederweg 1 http://www.objektfabrik.de D-71640 Ludwigsburg http://joachimtuchel.wordpress.com Telefon: +49 7141 56 10 86 0 Fax: +49 7141 56 10 86 1 |
Joachim,
Are you inspecting execution of the callbacks on the server-side only? It seems that when you say that “the browser is blocking” you are actually saying that the request for the callback is not *processed* while the ajax load is executing? To verify: do you see the browser performing a request in the browser developer tools when you click the link? Seaside requires all requests for the same session to be processed sequentially. So, callbacks will not execute as long as the server is processing any other callback for the same session. It seems to me that this is what you are experiencing. This has to do with how Seaside manages session state for you. Thinking about it: I’m not sure if it would be possible to have an exception for some ajax callbacks. At the very least, it would put a responsibility of managing the session state concurrency conflicts in the hands of the application developer. However, this does not solve your problem. Do you have a bit more information on why these components are rendering slowly? Is it the rendering phase or is the retrieval of the data for these components slow? Johan
_______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by jtuchel
Joachim,
Are you inspecting execution of the callbacks on the server-side only? It seems that when you say that “the browser is blocking” you are actually saying that the request for the callback is not *processed* while the ajax load is executing? To verify: do you see the browser performing a request in the browser developer tools when you click the link? Seaside requires all requests for the same session to be processed sequentially. So, callbacks will not execute as long as the server is processing any other callback for the same session. It seems to me that this is what you are experiencing. This has to do with how Seaside manages session state for you. Thinking about it: I’m not sure if it would be possible to have an exception for some ajax callbacks. At the very least, it would put a responsibility of managing the session state concurrency conflicts in the hands of the application developer. However, this does not solve your problem. Do you have a bit more information on why these components are rendering slowly? Is it the rendering phase or is the retrieval of the data for these components slow? Johan
_______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by Johan Brichau-2
Hi Johan,
what you describe fits well into my observations (or vice versa).... Am 20.11.15 um 08:56 schrieb Johan Brichau: Joachim,Of course the use of "blocking" was wrong. The browser is not blocking, I just see no reaction to my click on the "normal" link before all the all Ajax requests are finished - and it seems you just described why that is. The link does a show:, so the browser navigates away from the page the very instant the longest running ajax request is done. The dev toos in Firefox are cleared in that moment, so I cannot see anything of that "normal" request. While the two Ajax requests are being processed, I cannot see that "normal" request being sent to the server (but I should, even if the server doesn't react). So this explains a lot. This means we can cheat a little by showing the page earlier, but it won't be reacting to menu selections any sooner. Unless we do some "use another session (or even server) to collect the data" magic. Yes, I was hoping to not only make page load times shorter, but also let the user click sooner... Especially since our dashboard will grow and allow more data-intensive reporting over time. So far I seem to have learned that this power wouldn't be put in good hands in my case ;-) One stupid question that wants to be asked: AFAIK there is no way of stopping the server side from processind Ajax requests? I know you can cancel the ajax request on the client side, but this is just keeping the browser from waiting, right? Thinking about this a little further, I could possibly implement some crude special ajax call that stops the ajax processing on the server side and kills those background-processes on the server side (currently, they are not forked processes, but they could be) whenever the user clicks one of the links in the menu.... Not sure I really like the idea, but maybe it would work... It is a lot of data that has to be processed on the smalltalk side. So no Seaside problem here. Glorp is probably the busiest component in this processing. Oh my, so I have to put on my Architect's hat again and see how we can speed up the data collection before we add more widgets to the dashboard.
-- ----------------------------------------------------------------------- Objektfabrik Joachim Tuchel [hidden email] Fliederweg 1 http://www.objektfabrik.de D-71640 Ludwigsburg http://joachimtuchel.wordpress.com Telefon: +49 7141 56 10 86 0 Fax: +49 7141 56 10 86 1 _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Joachim,
The Chrome devtools have an option to “preserve log” in the network tab. This will not clear the tab on a page load.
The best solution for this is to fork a background process to collect the data in your component and only render the component when the data is present. Instead of using a ‘long running ajax request’ you poll the server with short requests until the data is ready and the component can be rendered. This is exactly what we do for tasks that take a long time to fetch data (e.g. rendering documents, long-running database queries, etc…). A spinner is shown on the webpage and the server is polled at seconds intervals until it effectively returns a rendered component. The data for that component is generated by a background process. This perfectly fits your decoration implementation. Something along these lines (disclaimer: untested code written in email client :) : replaced ifTrue: [div with: [self renderNextOn: html]] ifFalse: [ html document addLoadScript: (self loadScriptOn: html). div with: [ html image src: someSpinnerImage html space; text: self message]] (html jQuery: self idSelector) load html: [:r | self isDataReady ifTrue:[ replaced := true. self renderNextOn: html] ifFalse: [ r addLoadScript: (self loadScriptOn: r) ]). Of course, this is a very simple and naive implementation and you might want to add more features to the decorator code (such as a limit to the number of retries, or handling errors, etc…). But I think you get the basic idea. Hope this helps! Johan _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
The code I sent before will poll a bit too quickly :) I forgot to add a wait on the client: replaced ifTrue: [div with: [self renderNextOn: html]] ifFalse: [ html document addLoadScript: (self loadScriptOn: html). div with: [ html image src: someSpinnerImage html space; text: self message]] (html jQuery: self idSelector) load html: [:r | self isDataReady ifTrue:[ replaced := true. self renderNextOn: html] ifFalse: [ r addLoadScript: ((self loadScriptOn: r) timeout: 1000) ]). _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Johan,
thanks a lot for this idea and code draft. It is of course exactly what I need. Given that we use that background process thing at another place (show a progress dialog for a long running process), it is sad but trrue I didn't think of the same technique for this purpose. But of course this is the perfect thing to do. Thus the Ajax's will be short running and the browser won't wait for the data. Definitely worth it. Once again: thanks a lot for your guidance and help! I still hope one day I can give something back. Maybe a drink in Prague at ESUG 2016 counts as a first attempt? ;-) Joachim Am 20.11.15 um 09:52 schrieb Johan Brichau-2 [via Smalltalk]:
-- ----------------------------------------------------------------------- Objektfabrik Joachim Tuchel [hidden email] Fliederweg 1 http://www.objektfabrik.de D-71640 Ludwigsburg http://joachimtuchel.wordpress.com Telefon: +49 7141 56 10 86 0 Fax: +49 7141 56 10 86 1 |
In reply to this post by Johan Brichau-2
Hi Johan,
Adding a loadScript during an ajax callback is a really cool trick. I've got this working - in principle ;-) There is, however, a problem: jQuery's load doesn't support timeouts (nor any other paramters) . So I need to rewrite load as an ajax call which supports the timout parameter. Currently struggling a bit, but it's a good learning experience ;-) Again, thanks a lot, you've added a few important building blocks to the solution! Joachim Am 20.11.15 um 10:06 schrieb Johan Brichau:
_______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by jtuchel
Hi Joachim,
I’m not really sure what “timeout” you are referring to, but your reply makes me think of an issue (see below). The timeout method I used in my code snippet corresponds to JavaScript’s setTimeout function wrapped around the ajax request. So, in that sense, any JS expression supports that. BUT, an issue regarding the #timeout: message pops to my mind: There are two unrelated implementations of the #timeout: message. The one on (JSObject>>timeout:) is to wrap a JS statement in a setTimeout function, the other one on (JQAjaxSetup>>timeout:) is to set a timeout value for the ajax request. Unfortunately, the latter overrides the former. I suspect that the code I sent you hits that issue. You can solve it by sending "addDecoration: (JSTimeout duration: aDuration)” instead of #timeout:. I got bitten by this before. I ignored it (working around it by using #addDecoration:). A colleague of mine got bitten just a couple of weeks ago. I think you got bitten too now. I think I should no longer ignore this unpolymorphic override anymore :/ [1]
_______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Hi Johan,
I was referring to the timeout: parameter of $.ajax() which is not supported by .load() (see here: http://stackoverflow.com/questions/16129292/how-do-i-set-a-timeout-in-load-jquery-for-this-particular-example). But the wrapping of the load()-call within a setTimout() works perfectly. So your suggestion of "addDecoration: (JSTimeout duration: aDuration)" works perfectly! So you taught me at least 3 important lessons today: 1. I can addLoadScript: in an ajax callback 2. addDecoration: in JSObjects to wrap stuff into a function 3. The handling of Ajax Callbacks on the Seaside Server blocks "normal" callbacks (I know of no better way to name it) We now have a dashboard that reacts to clicks immediately. There is one thing with a bitter taste for now: the server side Ajax processing is not stopped, so the background process still burns cycles although nobody is interested in its results any more. It should be easy to do this, because it is just a question of terminating background processes and keep track of what background processes are currently running for this session. Combined with another Ajax call and a bit of bookeeping we'll be able to save cycles should the need arise. For now we just enjoy the improvements ;-) Thanks for great help! Joachim Am 21.11.15 um 09:14 schrieb Johan Brichau: Hi Joachim, _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Free forum by Nabble | Edit this page |