Loading brython outside of body onload

95 views
Skip to first unread message

Hiren Patel

unread,
Nov 5, 2016, 4:54:15 AM11/5/16
to brython
Given brython's loading issues (can be slow due to many http calls for imports), my opinion is that loading it in body onload can be quite bad to page responsiveness and load time. I had opened a bug report for it (https://github.com/brython-dev/brython/issues/478). As seen in the first comment on the issue page, it seems to be a bug, and possible a simple to fix one. I am not a js expert and the brython js code is not the easiest to follow. Is there a contributor that could look into the issue for me?

I know the load time and speed has been an ongoing effort and issue for brython, and it is becoming something of an issue in the apps I use it with. Since brython also does not offer an option to compile to js server side, I may have to investigate other solutions. Before doing so though, I wanted to find out what the status of two things in brython are, first being compile to js, and the other dealing with load times. Modules loaded by brython.js (such as ajax.py or json.js) are given url parameters that look like the current timestamp, which cause them to be loaded each time (effectively sidestepping browser cache), what is the reason for this? Could load time not be speeded up a whole lot by letting those sub modules also be taken from the cache?

Eric S. Johansson

unread,
Nov 6, 2016, 12:33:05 PM11/6/16
to brython


On Saturday, November 5, 2016 at 4:54:15 AM UTC-4, Hiren Patel wrote:
Given brython's loading issues (can be slow due to many http calls for imports), my opinion is that loading it in body onload can be quite bad to page responsiveness and load time. I had opened a bug report for it (https://github.com/brython-dev/brython/issues/478). As seen in the first comment on the issue page, it seems to be a bug, and possible a simple to fix one. I am not a js expert and the brython js code is not the easiest to follow. Is there a contributor that could look into the issue for me?

I know the load time and speed has been an ongoing effort and issue for brython, and it is becoming something of an issue in the apps I use it with. Since brython also does not offer an option to compile to js server side, I may have to investigate other solutions. Before doing so though, I wanted to find out what the status of two things in brython are, first being compile to js, and the other dealing with load times. Modules loaded by brython.js (such as ajax.py or json.js) are given url parameters that look like the current timestamp, which cause them to be loaded each time (effectively sidestepping browser cache), what is the reason for this? Could load time not be speeded up a whole lot by letting those sub modules also be taken from the cache?

I've given the import problem a bit of thought and the most obvious solution is one where we can aggregate import requests. The basic concept is caching based on the principle of "if you need this, then you will need that". If we do this dynamically, and I believe this to be the "best" way, we would need a server-side application that would be the target of each import request. Each time import is requested, the import information is is cached. How we use that cache varies on the bulk import mechanism.

Reusing the existing VFS.js mechanism means that every element we cache, gets put into a VFS.js file. If possible, we should also validate that every element in the VFS.js file is current and update the element if it is not.

The advantage to reusing VFS.js is that we maintain the simplicity of the basic structure in that if all the imports are satisfied, we just fetch one file without any server-side applications. I don't know enough about the structure to understand the disadvantages. One potential disadvantage might be the time for construction or difficulty of dynamic updates.

The other option is a single import server-side application which lets us answer the "I need this module" with "here's that module and here's everything else you will need". The advantages is the "and here's everything else" can be created at the last minute or from a cache data store allowing a trade-off between ease of detecting changes in the modules and speed of bulk response. As I see it, bulk response creation at the last minute would be used in a development environment where things are rapidly changing and a more stable cached model would be used in a production environment where you need speed.

The difference between the two approaches is that VFS.js contains a random collection modules and if you need only one module and its dependence, you download everything. As a documentation said, for the system modules, the VFS.js is 2 MB. The second option would like to request a module and then get that module and everything it depends on. Subsequent requests would load duplicates of mutual dependencies if the caching was not smart. Some ways of making caching smarter might be making the request say something like "I need this, I have this" and the response contains the difference between what you have and what you will need.

Thoughts?

Jonathan Verner

unread,
Nov 7, 2016, 3:24:02 AM11/7/16
to brython
I don't think a serverside application is a good idea for several reasons:

  -- it would need node.js to compile the modules (the compiler is written in javascript)
  -- it would add unneeded complexity to production (running a server for brython caching in addition to the application server)
  -- it would be quite complicated to write

A better approach, IMHO, is to precompile stuff needed by the application into a single file
which would be deployed to production and could be cached by the browser.

See also the discussion on the Brython Github Issue #491.

123 456

unread,
Nov 7, 2016, 1:25:41 PM11/7/16
to bry...@googlegroups.com
On Mon, Nov 7, 2016 at 3:24 AM, Jonathan Verner <jona...@temno.eu> wrote:
> I don't think a serverside application is a good idea for several reasons:
>
> -- it would need node.js to compile the modules (the compiler is written
> in javascript)

currently, py_VFS.js looks like it is stripped python stuffed into a
javascript dictionary where each key is the module name. It would be
nice if we could precompile into JavaScript but it wouldn't have to be
done with node.js. it's possible we could do it in the browser itself
as the compile environment and pushing the transpiled JS to
server-side.

> -- it would add unneeded complexity to production (running a server for
> brython caching in addition to the application server)

I agree it would add complexity but if I can eliminate tens of seconds
of wait time on start, I would argue for it as needed complexity.

> -- it would be quite complicated to write

The simple minimum viable version would take a couple of days to
write. A truly optimized version that adapts to different workloads
would be quite complicated but it isn't needed until you can actually
measure usage profiles.

For minimum viable, I would have one server-side program. To the
outside world, it would look like a URL request for an import file.
But instead of a simple file fetch and return, it would be a
relatively small bit of code that would return the import request and
add it to the "local" VFS.js if it doesn't exist. To maintain
invisible behavior, it would return the import requested file. The
next time the application runs, it would get that module from the
VFS.js bulk load.

Eventually, there will be no explicit module requests as all of them
will have been cached.

>
> A better approach, IMHO, is to precompile stuff needed by the application
> into a single file which would be deployed to production and could be cached by the browser.

Something like, VFS.js, yes?

Pierre Quentel

unread,
Nov 7, 2016, 4:02:55 PM11/7/16
to brython

I suggest all readers to read the thread on Github issue #491. I will summarize the results below.

The time taken by an import is the combination of 2 factors :
1 - the time taken by an Ajax call to get the code
2 - the conversion of Python to Javascript

The current optimisation is to group (minified) Python source in py_VFS.js, to avoid factor 1.

To avoid factor 2, we need to precompile Python into Javascript and store the result somewhere.

I have written a program to generate compiled Javascript script for all the Python scripts in the standard distribution (BTW it doesn't use node.js, just a script running in the browser that compiles all the source files in py_VFS.js and sends the result to a local Python script by an Ajax call). The problem is that a precompiled JS script is generally in the order of 10 times bigger than the Python source. This means that a single file with all the precompiled standard library - ie the suppression of both factors 1 and 2 - is unfortunately not an option.

We could put all the precompiled scripts in a specific folder and change the import mechanism to load these files : this is avoiding factor 2 but keeping factor 1. I did it, but the result is only marginally faster than the current solution with py_VFS.js (see the figures in issue #491), and the test I made may not be a good example of a Web application. Anyway, the improvement is not clear enough to make it the default, change the way import works and to impose the extra disk space taken by the precompiled scripts.

Of course some might say that it's not necessary to precompile the whole standard distribution and that we could only select those that are used by a specific application. So I developed a program to list them. The result is also in issue #491 : even for a very simple script, 2/3rd of the standard distribution is required...

For the moment I am working on an extended version of py_VFS.js, where not only the standard distribution but also the application-specific modules and packages (Python source code) would be put in a bundled JS file.
 

Hiren Patel

unread,
Dec 19, 2016, 6:13:00 AM12/19/16
to brython
Hi,

For point 1, when brython does ajax to get pieces for the imports, chrome dev tools shows that it uses the url forms for example of https://10.0.0.214/static/brython/Lib/browser/timer.py?v=1482145462659, when I reload the page, v=xxx has changed, suggesting it is a timestamp of sorts. If this was not the case then my webserver could set caching policies to allow the browser to cache these. Why does it append the v=xxx, and is that really needed?

Hiren Patel

unread,
Dec 19, 2016, 6:40:45 AM12/19/16
to brython

I have written a program to generate compiled Javascript script for all the Python scripts in the standard distribution (BTW it doesn't use node.js, just a script running in the browser that compiles all the source files in py_VFS.js and sends the result to a local Python script by an Ajax call). The problem is that a precompiled JS script is generally in the order of 10 times bigger than the Python source. This means that a single file with all the precompiled standard library - ie the suppression of both factors 1 and 2 - is unfortunately not an option.

For the above, is the script available to try out. Even though the js could be large, it is text, so for web servers configured to response with gzip'd content, it could vastly reduce the size?

On Monday, 7 November 2016 23:02:55 UTC+2, Pierre Quentel wrote:
On Monday, 7 November 2016 23:02:55 UTC+2, Pierre Quentel wrote:
On Monday, 7 November 2016 23:02:55 UTC+2, Pierre Quentel wrote:
Reply all
Reply to author
Forward
0 new messages