Page MenuHomePhabricator

mw.loader should load urls of a module in parallel
Closed, DeclinedPublic

Description

When using the mw.loader.using() method, The modules are requested in synchronous mode, because inside the using function, the request() call is done without specifying the mode, so the modules will be requested one by one, the script waiting for one module to be ready before calling the next one.

Perhaps this can be usefull for some purpose, but for some other purpose, when you have to call several script subpages before launching something and if the loading order doesn't matter, the result is a waste of time and a very slow loading.

I ask for a fix in mw.loader.using method, with a new parameter (async ?) to be passed to the request() call.

See : fr:wp:Special:Diff/113497286.

Event Timeline

Dr_Brains raised the priority of this task from to Low.
Dr_Brains updated the task description. (Show Details)
Dr_Brains added a project: JavaScript.
Dr_Brains added a subscriber: Dr_Brains.
Krinkle renamed this task from mw.loader.using loads modules one by one. I would want to load all modules at the same time to mw.loader.using should not load modules in separate requests.Apr 28 2015, 5:21 PM
Krinkle moved this task from Inbox to Backlog on the MediaWiki-ResourceLoader board.

That is probably because you use Ressourceloader : it makes a unique file with all the modules you asked

Try this in a gadget or in any .js user subpage, where url1, url2, url3 are real .js pages url (mediawiki or user namspace) :

mw.loader.implement( "mydependencies", [ "url1", "url2", "url3" ], {}, {}, {} );
mw.loader.using( "mydependencies", function(){ alert("Done!"); });

Then, you will see in the firefox monitor that one module (url1, url2, etc...) starts to be loaded only when the previous one is fully loaded.

So, if your gadget has several dependencies, it takes a (too) long time before it really starts.

Krinkle renamed this task from mw.loader.using should not load modules in separate requests to mw.loader should load urls of a module in parallel.May 17 2015, 8:55 PM

That is probably because you use Resourceloader : it makes a unique file with all the modules you asked.

Yes, that's the purpose of mw.loader. To ensure one or more registered ResourceLoader modules are loaded.

Try this in a gadget or in any .js user subpage, with url1, url2, url3 as real .js pages (mediawiki or user) :

mw.loader.implement( "mydependencies", [ "url1", "url2", "url3" ], {}, {}, {} );
mw.loader.using( "mydependencies", function(){ alert("Done!"); });

Then, you will see in the firefox monitor that one module (url1, url2, etc...) starts to be loaded only when the previous one is fully loaded.

So, if your gadget has several dependencies, it takes a (too) long time before it really starts.

In general mw.loader does not make multiple requests when loading modules. Modules are registered on the server by extensions or gadgets, and are loaded in large batches.

Unrelated to this, some modules have cache control group. Those modules are loaded in separate concurrent requests. These requests, however, are made in parallel; not one after the other.

Assume an example module foo, having foo.a.js and foo.b.js. When loading "foo" the server uses mw.loader.implement and provide a combined package containing both files at once. But, in debug mode, it returns an array of urls to each individual file. In that cases, the client requests one file after the other. This has to be this way because each file depends on the previous file. As mentioned, this is only for debug module and intentionally inefficient.

It appears you are using mw.loader.implement to stash source code of something that is not a ResourceLoader module. This is not supported. If you wish to load arbitrary source code not related to ResourceLoader modules, please do not use mw.loader.implement. As you observed, this does not do what you want and is bound by restrictions (file dependencies) that do not apply to your code.

For loading plain JavaScript files, you can use jQuery:

$.when(
  $.ajax({ url: "url1", dataType: 'script', cache: true }),
  $.ajax({ url: "url2", dataType: 'script', cache: true }),
  $.ajax({ url: "url3", dataType: 'script', cache: true })
}).done(function () {
  alert( 'Done!' );
});

Or, if you like abstraction:

$.when.apply( null, $.map( [ "url1", "url2", "url3" ], function ( url ) {
  return $.ajax({ url: url, dataType: 'script', cache: true });
} ) ).done( function () {
  alert( 'Done!' );
} );

I hope this is useful to you.

Thanks,
– Krinkle

Krinkle claimed this task.

Declining this request because the behaviour of synchronous one-by-one requests for urls is intentional. Changing this is now compatible with how ResourceLoader's debug mode operators.

Note that this behaviour does not apply to the main production mode, in which things are either combined into a single request or requested concurrently.

To requests separate unrelated files make separate calls to mw.loader.load( url ), or use jQuery for requesting related files with a callback.

Note that one may also try to promote the script to a gadget (with support of local administrators on the relevant wiki), in which case ResourceLoader can be used.

The second example do what I need, so I guess it will be OK.