tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

deferred-promise-utils.js (2722B)


      1 /**
      2 * This file co-works with a html file and utils.js to test a promise that
      3 * should be deferred during prerendering.
      4 *
      5 * Usage example:
      6 *  Suppose the html is "prerender-promise-test.html"
      7 *  On prerendering page, prerender-promise-test.html?prerendering:
      8 *    const prerenderEventCollector = new PrerenderEventCollector();
      9 *    const promise = {a promise that should be deferred during prerendering};
     10 *    prerenderEventCollector.start(promise, {promise name});
     11 *
     12 *  On the initiator page, prerender-promise-test.html:
     13 *   execute
     14 *    `loadInitiatorPage();`
     15 */
     16 
     17 // Collects events that happen relevant to a prerendering page.
     18 // An event is added when:
     19 // 1. start() is called.
     20 // 2. a prerenderingchange event is dispatched on this document.
     21 // 3. the promise passed to start() is resolved.
     22 // 4. addEvent() is called manually.
     23 class PrerenderEventCollector {
     24  constructor() {
     25    this.eventsSeen_ = [];
     26    new PrerenderChannel('close').addEventListener('message', () => {
     27      window.close();
     28    });
     29  }
     30 
     31  // Adds an event to `eventsSeen_` along with the prerendering state of the
     32  // page.
     33  addEvent(eventMessage) {
     34    this.eventsSeen_.push(
     35        {event: eventMessage, prerendering: document.prerendering});
     36  }
     37 
     38  // Starts collecting events until the promise resolves. Triggers activation by
     39  // telling the initiator page that it is ready for activation.
     40  async start(promise, promiseName) {
     41    assert_true(document.prerendering);
     42    this.addEvent(`started waiting ${promiseName}`);
     43    promise
     44        .then(
     45            () => {
     46              this.addEvent(`finished waiting ${promiseName}`);
     47            },
     48            (error) => {
     49              if (error instanceof Error)
     50                error = error.name;
     51              this.addEvent(`${promiseName} rejected: ${error}`);
     52            })
     53        .finally(() => {
     54          // Used to communicate with the main test page.
     55          const testChannel = new PrerenderChannel('test-channel');
     56          // Send the observed events back to the main test page.
     57          testChannel.postMessage(this.eventsSeen_);
     58          testChannel.close();
     59        });
     60    document.addEventListener('prerenderingchange', () => {
     61      this.addEvent('prerendering change');
     62    });
     63 
     64    // Post a task to give the implementation a chance to fail in case it
     65    // resolves a promise without waiting for activation.
     66    setTimeout(() => {
     67      // Used to communicate with the initiator page.
     68      const prerenderChannel = new PrerenderChannel('prerender-channel');
     69      // Inform the initiator page that this page is ready to be activated.
     70      prerenderChannel.postMessage('readyToActivate');
     71      prerenderChannel.close();
     72    }, 0);
     73  }
     74 }