Page Ready

Last modified by Marius Dumitru Florea on 2022/03/28

Most of XWiki's JavaScript code is organized in modules following the Asynchronous module definition (AMD) specification. These modules are loaded asynchronously, most of the time after the window load event is fired so it's not easy to know when the page is fully ready for user interaction, i.e. when all the resources have been loaded and there are no pending HTTP requests or promises. Executing code after the page is ready is important for instance when performing client-side PDF export: the page should have all its elements ready, including those added dynamically and asynchronously, before we tell the browser to print the page. Similarly, when running automated functional tests we need to wait for the page to be ready before simulating user interaction, otherwise we end up having many failing flaky tests. The xwiki-page-ready JavaScript module satisfies this need. Here's how you can use it:

require(['xwiki-page-ready'], function(pageReady) {
  pageReady.afterPageReady(() => {
    console.log('Page is ready!');
  });
});

The xwiki-page-ready module intercepts automatically:

  • window load event
  • all XMLHttpRequests
  • all fetch() requests
  • all script tag injections

(that happen around page load) and delays the page ready until they all finish. So normally you only need to know about afterPageReady(), as shown above. Note that the callback passed to afterPageReady() can return a promise in order to delay the other page ready callbacks. This is useful if you want to execute an asynchronous process after the page is ready but you also want to make the other callbacks wait (e.g. you want the print to PDF to include your changes):

require(['xwiki-page-ready'], function(pageReady) {
  pageReady.afterPageReady(() => {
   return new Promise((resolve, reject) => {
     // Do some asynchronous processing and then call resolve() in order
     // to allow the other page ready callbacks to be executed.
   });
  });
});

If you have JavaScript code that executes after the page is loaded with some delay and you want to also delay the page ready then here's how you can do it:

require(['xwiki-page-ready'], function(pageReady) {
  pageReady.delayPageReady(new Promise((resolve, reject) => {
   // Perform some asynchronous action and call resolve() when done.
 }), 'the reason for delay');
});

delayPageReady accepts a promise, that delays the page ready until settled (either fulfilled or rejected), and an optional reason string, which is useful for debugging (see below).

When the page is ready the HTML root element is marked accordingly using the data-xwiki-page-ready="true" attribute. If this doesn't happen then you can inspect the pending delays (that prevent the page ready) using the following code (even directly from the JavaScript console):

require(['xwiki-page-ready'], function(pageReady) {
  console.log(pageReady.getPendingDelays());
});

The optional reason parameter passed to delayPageReady prooves very useful in this case to understand where the problem is (e.g. to understand which script or which fetch request are blocking the page ready).

Get Connected