Having been in this industry for some time now, I can’t help noticing things cropping up again every so often. It would appear that, as in fashion, if one can’t invent something new, one can always take an idea from the past and simply wrap it differently. A good example in this industry is the mainframe. How many times has it been said that the mainframe and the central model are dead, and that decentralisation is the way to go? Meanwhile Sun made an attempt with their (virtual display) thin clients. And of course there is now Web 2.0 and the online office suits.
The mainframe isn’t dead btw. IBM is even building new ones (http://www.informationweek.com/management/showArticle.jhtml?articleID=199201820) for better performance in virtual worlds like Second Life (which is another example of centralised apps).
You might say that I’m comparing apples and oranges. No, I don’t mind these evolutions, and yes, the technologies are different (no longer real dumb terminals to name at least one). But the philosophy remains the same: no thick client and thus no extra software on the client. Taking the bend too sharp, I would say that it’s old wine in new bottles.
I had the same feeling when I came across this web log the other day. The
Do the request
What’s it all about? The default browser/server behaviour in original HTTP/1.0 protocol description closes the connection after the completion of a request. This results in at least 2 RTTs (round-trip time) being required for fetching every object:
1. TCP handshake
That means a lot of requests e.g. for a page containing 10 graphics, a CSS include and JS file. Things changed in 1999 with HTTP/1.1 when parallel requests became possible. Despite that, browsers still don’t load all of the elements of a page in one go. It all depends on your browser settings and whether they follow the standard guideline of downloads in parallel per host name. You can check (and eventually modify) things by yourself.
In Microsoft Internet Explorer, look in regedit for the key HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionInternet Settings
and the DWORD MaxConnectionsPerServer.
In Firefox, look in the about:config for
Several “solutions” for better performance have been launched over the years. The funniest was to decrease the number of components to an absolute minimum. That reminded me of a tip on how to reduce your phone bill in some miser’s guide which was – don’t use the phone for making calls, make sure to get called.
The best method is to make sensible use of components. The earlier mentioned web log concentrates on bundling all CSS and JS components into the calling HTML page.
Why doesn’t one put all the code in the HTML straight away? Indeed there is no objection to that. If you want to prevent clutter or want for example to reuse, or group, code, you will need to put the code in separate instances. So you need to find a way to bundle the components in such way that the code only requires one request. In the afore-mentioned web log, one can fix things with a module for the Apache server.
Within the BSP environment one doesn’t need to go as far as to create server code. In fact, if desired, one doesn’t need to code anything.
The first prerequisite is not to import the CSS and JS files as MIMEs. MIMEs will be considered as separate objects and will always be loaded (if not available in the cache) separately. In fact, I would even recommend uploading only binary content (jpeg, gif, flash, etc) as MIME. All the other content should be considered to be normal BSP pages or page fragments. It’s a common misunderstanding that with BSP pages and fragments only BSP/ABAP code should be provided. You can code anything in them. It has the advantage that you don’t need to download, edit things in a separate editor and upload it as MIME again whenever you want to modify something in the CSS or JS code.
Choosing page fragments would solve the bundling immediately. Page fragments will result in one page needing to be retrieved. I’m not so keen on this solution. To be honest, I hate page fragments when it comes to coding (certainly when a fragment is used in multiple BSP pages) and debugging (in production environments).
Therefore, I looked for a solution which retrieved all the files needed to be included in a BSP page. The result is an application method with two import parameters:
the name of the application
a string with all the names of the JS and CSS files, separated by spaces.
The returning parameter is a string containing all the JS and CSS content
The code looks like this:
DATA: p_key TYPE o2pagkey,l_layout TYPE o2pageline_table,
p_data TYPE REF TO cl_o2_api_pages, wa TYPE o2pageline,
pages TYPE TABLE OF string, wp TYPE string.
p_key-applname = application_name.
Then in order to split the names string in to a table.
SPLIT page_names AT space INTO TABLE pages.
We loop round that table
LOOP AT pages INTO wp.
We retrieve the ‘page’ content. That means that the JS and CSS are stored in BSP pages.
p_key-pagekey = wp.
TRANSLATE p_key-applname TO UPPER CASE.
TRANSLATE p_key-pagekey TO UPPER CASE.
CALL METHOD cl_o2_api_pages=>load_with_access_permission
p_mode = ‘SHOW’
p_pagekey = p_key
p_version = ‘A’
p_page = p_data
OTHERS = 1.
CALL METHOD p_data->get_page
p_content = l_layout
OTHERS = 1.
Each retrieved page is stored in a table, so we need to loop over it and concatenate the table row to the result, with a new line after each row
LOOP AT l_layout INTO wa.
CONCATENATE content cl_abap_char_utilities=>newline wa-line INTO content.
As you can see, it’s rather simple code. I’ve done this on an application level, but one could consider making a BSP extension (http://help.sap.com/saphelp_nw2004s/helpdata/en/f8/7e1d3c55a0f503e10000000a114084/frameset.htm) of it. It’s a bit out of the scope of this web log to explain this. The afore-mentioned help, and the numerous web logs on SDN concerning this matter can certainly help you further.
Now what is the performance gain with this method? Well, I first made a page that included 2 CSS files coded the classical way.
Then I measured the response times with Firebug (Firefly Dreams):
</p> <p><img height='57' alt='image' width='600' src='https://weblogs.sdn.sap.com/weblogs/images/19902/load_before.gif' border='0'/></p> <p>After that, I made a new page which used the application method.</p> <p> </p> <pre><p>main_bis.htm</p><p> </p><%@page language="abap"%> <html> <head> <style type="text/css"> <%=application->load_it( APPLICATION_NAME = runtime->application_name PAGE_NAMES = 'h1.css h2.css' )%> </style> </head> <body>
font-family: Georgia, “Times New Roman”, Times, serif;
font-family: Georgia, “Times New Roman”, Times, serif;
The result is: