mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1483038 - Optimize L10nRegistry generator to early exit on missing resources. r=mossop
Optimize L10nRegistry generator to early exit on missing resources. Differential Revision: https://phabricator.services.mozilla.com/D3394 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
53f1370b5f
commit
a7959b6272
@ -95,26 +95,18 @@ const L10nRegistry = {
|
||||
const sourcesOrder = Array.from(this.sources.keys()).reverse();
|
||||
const pseudoNameFromPref = Services.prefs.getStringPref("intl.l10n.pseudo", "");
|
||||
for (const locale of requestedLangs) {
|
||||
for (const fetchPromises of generateResourceSetsForLocale(locale, sourcesOrder, resourceIds)) {
|
||||
const ctx = await Promise.all(fetchPromises).then(
|
||||
dataSets => {
|
||||
const ctx = new MessageContext(locale, {
|
||||
...MSG_CONTEXT_OPTIONS,
|
||||
transform: PSEUDO_STRATEGIES[pseudoNameFromPref],
|
||||
});
|
||||
for (const data of dataSets) {
|
||||
if (data === null) {
|
||||
return null;
|
||||
}
|
||||
ctx.addResource(data);
|
||||
}
|
||||
return ctx;
|
||||
},
|
||||
() => null
|
||||
);
|
||||
if (ctx !== null) {
|
||||
yield ctx;
|
||||
for await (const dataSets of generateResourceSetsForLocale(locale, sourcesOrder, resourceIds)) {
|
||||
const ctx = new MessageContext(locale, {
|
||||
...MSG_CONTEXT_OPTIONS,
|
||||
transform: PSEUDO_STRATEGIES[pseudoNameFromPref],
|
||||
});
|
||||
for (const data of dataSets) {
|
||||
if (data === null) {
|
||||
return;
|
||||
}
|
||||
ctx.addResource(data);
|
||||
}
|
||||
yield ctx;
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -190,7 +182,7 @@ const L10nRegistry = {
|
||||
* @param {Array} [resolvedOrder]
|
||||
* @returns {AsyncIterator<MessageContext>}
|
||||
*/
|
||||
function* generateResourceSetsForLocale(locale, sourcesOrder, resourceIds, resolvedOrder = []) {
|
||||
async function* generateResourceSetsForLocale(locale, sourcesOrder, resourceIds, resolvedOrder = []) {
|
||||
const resolvedLength = resolvedOrder.length;
|
||||
const resourcesLength = resourceIds.length;
|
||||
|
||||
@ -200,18 +192,36 @@ function* generateResourceSetsForLocale(locale, sourcesOrder, resourceIds, resol
|
||||
for (const sourceName of sourcesOrder) {
|
||||
const order = resolvedOrder.concat(sourceName);
|
||||
|
||||
// We bail only if the hasFile returns a strict false here,
|
||||
// because for FileSource it may also return undefined, which means
|
||||
// that we simply don't know if the source contains the file and we'll
|
||||
// have to perform the I/O to learn.
|
||||
if (L10nRegistry.sources.get(sourceName).hasFile(locale, resourceIds[resolvedOrder.length]) === false) {
|
||||
continue;
|
||||
// We want to bail out early if we know that any of
|
||||
// the (res)x(source) combinations in the permutation
|
||||
// are unavailable.
|
||||
// The combination may have been `undefined` when we
|
||||
// stepped into this branch, and now is resolved to
|
||||
// `false`.
|
||||
//
|
||||
// If the combination resolved to `false` is the last
|
||||
// in the resolvedOrder, we want to continue in this
|
||||
// loop, but if it's somewhere in the middle, we can
|
||||
// safely bail from the whole branch.
|
||||
for (let [idx, sourceName] of order.entries()) {
|
||||
if (L10nRegistry.sources.get(sourceName).hasFile(locale, resourceIds[idx]) === false) {
|
||||
if (idx === order.length - 1) {
|
||||
continue;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the number of resolved sources equals the number of resources,
|
||||
// create the right context and return it if it loads.
|
||||
if (resolvedLength + 1 === resourcesLength) {
|
||||
yield generateResourceSet(locale, order, resourceIds);
|
||||
let dataSet = await generateResourceSet(locale, order, resourceIds);
|
||||
// Here we check again to see if the newly resolved
|
||||
// resources returned `false` on any position.
|
||||
if (!dataSet.includes(false)) {
|
||||
yield dataSet;
|
||||
}
|
||||
} else if (resolvedLength < resourcesLength) {
|
||||
// otherwise recursively load another generator that walks over the
|
||||
// partially resolved list of sources.
|
||||
@ -346,10 +356,10 @@ const PSEUDO_STRATEGIES = {
|
||||
* @param {Array} resourceIds
|
||||
* @returns {Promise<MessageContext>}
|
||||
*/
|
||||
function generateResourceSet(locale, sourcesOrder, resourceIds) {
|
||||
return resourceIds.map((resourceId, i) => {
|
||||
async function generateResourceSet(locale, sourcesOrder, resourceIds) {
|
||||
return Promise.all(resourceIds.map((resourceId, i) => {
|
||||
return L10nRegistry.sources.get(sourcesOrder[i]).fetchFile(locale, resourceId);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -420,14 +430,14 @@ class FileSource {
|
||||
|
||||
fetchFile(locale, path) {
|
||||
if (!this.locales.includes(locale)) {
|
||||
return Promise.reject(`The source has no resources for locale "${locale}"`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const fullPath = this.getPath(locale, path);
|
||||
|
||||
if (this.cache.hasOwnProperty(fullPath)) {
|
||||
if (this.cache[fullPath] === false) {
|
||||
return Promise.reject(`The source has no resources for path "${fullPath}"`);
|
||||
return false;
|
||||
}
|
||||
// `true` means that the file is indexed, but hasn't
|
||||
// been fetched yet.
|
||||
@ -435,7 +445,7 @@ class FileSource {
|
||||
return this.cache[fullPath];
|
||||
}
|
||||
} else if (this.indexed) {
|
||||
return Promise.reject(`The source has no resources for path "${fullPath}"`);
|
||||
return false;
|
||||
}
|
||||
return this.cache[fullPath] = L10nRegistry.load(fullPath).then(
|
||||
data => {
|
||||
@ -443,7 +453,7 @@ class FileSource {
|
||||
},
|
||||
err => {
|
||||
this.cache[fullPath] = false;
|
||||
return Promise.reject(err);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ class CachedAsyncIterable extends CachedIterable {
|
||||
return {
|
||||
async next() {
|
||||
if (cached.length <= cur) {
|
||||
cached.push(await cached.iterator.next());
|
||||
cached.push(cached.iterator.next());
|
||||
}
|
||||
return cached[cur++];
|
||||
}
|
||||
@ -114,10 +114,10 @@ class CachedAsyncIterable extends CachedIterable {
|
||||
let idx = 0;
|
||||
while (idx++ < count) {
|
||||
const last = this[this.length - 1];
|
||||
if (last && last.done) {
|
||||
if (last && await (last).done) {
|
||||
break;
|
||||
}
|
||||
this.push(await this.iterator.next());
|
||||
this.push(this.iterator.next());
|
||||
}
|
||||
// Return the last cached {value, done} object to allow the calling
|
||||
// code to decide if it needs to call touchNext again.
|
||||
@ -322,7 +322,6 @@ class Localization {
|
||||
onChange() {
|
||||
this.ctxs = CachedAsyncIterable.from(
|
||||
this.generateMessages(this.resourceIds));
|
||||
this.ctxs.touchNext(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
const { DOMLocalization } =
|
||||
ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {});
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
/**
|
||||
* Polyfill for document.ready polyfill.
|
||||
@ -46,8 +47,9 @@
|
||||
|
||||
document.l10n = new DOMLocalization(resourceIds);
|
||||
|
||||
// Trigger the first two contexts to be loaded eagerly.
|
||||
document.l10n.ctxs.touchNext(2);
|
||||
const appLocales = Services.locale.getAppLocalesAsBCP47();
|
||||
const prefetchCount = appLocales.length > 1 ? 2 : 1;
|
||||
document.l10n.ctxs.touchNext(prefetchCount);
|
||||
|
||||
document.l10n.ready = documentReady().then(() => {
|
||||
document.l10n.registerObservers();
|
||||
|
Loading…
Reference in New Issue
Block a user