Bug 1456565 - Fetch fallback locale eagerly in Fluent. r=stas
authorZibi Braniecki <zbraniecki@mozilla.com>
Tue, 24 Apr 2018 10:31:59 -0700
changeset 472004 87498d129369be6098544c6345c6a3f8f363094c
parent 472003 787d7f8d7a5d35675639e03cd8a59a1f91e88f00
child 472005 681cf57b9ff3a8e6493ef5e42e4fc6289db469d2
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersstas
bugs1456565
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1456565 - Fetch fallback locale eagerly in Fluent. r=stas MozReview-Commit-ID: A9wBGxzdD2m
intl/l10n/Localization.jsm
intl/l10n/l10n.js
--- a/intl/l10n/Localization.jsm
+++ b/intl/l10n/Localization.jsm
@@ -22,27 +22,27 @@
 /* global console */
 
 const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", {});
 const { L10nRegistry } = ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm", {});
 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
 const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm", {});
 
 /*
- * CachedIterable caches the elements yielded by an iterable.
+ * CachedAsyncIterable caches the elements yielded by an iterable.
  *
  * It can be used to iterate over an iterable many times without depleting the
  * iterable.
  */
-class CachedIterable {
+class CachedAsyncIterable {
   /**
-   * Create an `CachedIterable` instance.
+   * Create an `CachedAsyncIterable` instance.
    *
    * @param {Iterable} iterable
-   * @returns {CachedIterable}
+   * @returns {CachedAsyncIterable}
    */
   constructor(iterable) {
     if (Symbol.asyncIterator in Object(iterable)) {
       this.iterator = iterable[Symbol.asyncIterator]();
     } else if (Symbol.iterator in Object(iterable)) {
       this.iterator = iterable[Symbol.iterator]();
     } else {
       throw new TypeError("Argument must implement the iteration protocol.");
@@ -77,21 +77,26 @@ class CachedIterable {
         return seen[cur++];
       }
     };
   }
 
   /**
    * This method allows user to consume the next element from the iterator
    * into the cache.
+   *
+   * @param {number} count - number of elements to consume
    */
-  touchNext() {
+  async touchNext(count = 1) {
     const { seen, iterator } = this;
-    if (seen.length === 0 || seen[seen.length - 1].done === false) {
-      seen.push(iterator.next());
+    let idx = 0;
+    while (idx++ < count) {
+      if (seen.length === 0 || seen[seen.length - 1].done === false) {
+        seen.push(await iterator.next());
+      }
     }
   }
 }
 
 /**
  * The default localization strategy for Gecko. It comabines locales
  * available in L10nRegistry, with locales requested by the user to
  * generate the iterator over MessageContexts.
@@ -117,17 +122,17 @@ class Localization {
    * @param {Function}      generateMessages - Function that returns a
    *                                           generator over MessageContexts
    *
    * @returns {Localization}
    */
   constructor(resourceIds, generateMessages = defaultGenerateMessages) {
     this.resourceIds = resourceIds;
     this.generateMessages = generateMessages;
-    this.ctxs = new CachedIterable(this.generateMessages(this.resourceIds));
+    this.ctxs = new CachedAsyncIterable(this.generateMessages(this.resourceIds));
   }
 
   /**
    * Format translations and handle fallback if needed.
    *
    * Format translations for `keys` from `MessageContext` instances on this
    * DOMLocalization. In case of errors, fetch the next context in the
    * fallback chain.
@@ -263,17 +268,17 @@ class Localization {
     }
   }
 
   /**
    * This method should be called when there's a reason to believe
    * that language negotiation or available resources changed.
    */
   onLanguageChange() {
-    this.ctxs = new CachedIterable(this.generateMessages(this.resourceIds));
+    this.ctxs = new CachedAsyncIterable(this.generateMessages(this.resourceIds));
   }
 }
 
 Localization.prototype.QueryInterface = XPCOMUtils.generateQI([
   Ci.nsISupportsWeakReference
 ]);
 
 /**
--- a/intl/l10n/l10n.js
+++ b/intl/l10n/l10n.js
@@ -41,17 +41,17 @@
       el => el.getAttribute("href")
     );
   }
 
   const resourceIds = getResourceLinks(document.head || document);
 
   document.l10n = new DOMLocalization(window, resourceIds);
 
-  // trigger first context to be fetched eagerly
-  document.l10n.ctxs.touchNext();
+  // Trigger the first two contexts to be loaded eagerly.
+  document.l10n.ctxs.touchNext(2);
 
   document.l10n.ready = documentReady().then(() => {
     document.l10n.registerObservers();
     document.l10n.connectRoot(document.documentElement);
     return document.l10n.translateRoots();
   });
 }