Мой вариант использования
Я работаю над большим приложением, где, в зависимости от роли пользователя, я загружаю / импортирую различные наборы модулей.Это метеорное приложение с Vue, vue-router & vue-i18n на внешнем интерфейсе, но без магазина, как vuex.
Каждый модуль имеет свои собственные маршруты, файлы перевода, API и пользовательский интерфейс.Вот почему мне нужно проверить, что каждый модуль и его переводы загружены, прежде чем я отобразлю основной интерфейс и навигацию (или, например, ярлыки элементов навигации, относящиеся к выгруженному модулю, не будут переведены, или локализованные маршруты вернут 404).
Существует ли как можно более простой шаблон для обеспечения загрузки всего?
Мой код и логика
Мой пример использованияболее сложный, чем я могу достичь с помощью Promise.all
afaik.
Я пытался давать вложенные обещания с комбинацией Promises.all
и then()
.
Чтобы подвести итог, порядок:
- загрузить базовый комплект
- войти в клиент
- импортировать языковой файл i18n для основногозатем связать для каждого модуля
- для каждого модуля, после того, как его языковой файл загружен и объединен в соответствующие сообщения i18n, мне нужно загрузить сам модуль (локализованные маршруты, пользовательский интерфейс ...)
Основная часть загрузки
Accounts.onLogin(function (user) {
let userRoles = Roles.getRolesForUser(Meteor.userId())
let promises = []
let lang = getDefaultLanguage()
promises.push(loadLanguageAsync(lang))
this.modulesReady = false
for (let role of userRoles) {
switch (role) {
case "user":
import { loadUserLanguageAsync } from "/imports/user/data/i18n"
promises.push(loadUserLanguageAsync(lang).then(import("/imports/user/")))
break
case "admin":
import { loadAdminLanguageAsync } from "/imports/admin/data/i18n"
promises.push(loadAdminLanguageAsync(lang).then(import("/imports/admin/")))
break
default:
break
}
}
return Promise.all(promises).then(function (values) {
this.modulesReady = true // my green flag, attached to the window object
})
})
основные функции загрузки языка
const loadedLanguages = []
// Load i18n
Vue.use(VueI18n)
export const i18n = new VueI18n()
export const getDefaultLanguage = () => {
let storedLanguage = window.localStorage.getItem(
Meteor.settings.public.brand + "_lang"
)
return Meteor.user() && Meteor.user().settings && Meteor.user().settings.language
? Meteor.user().settings.language
: // condition 2: if not, rely on a previously selected language
storedLanguage
? storedLanguage
: // or simply the browser default lang
navigator.language.substring(0, 2)
}
export const loadLanguage = (lang, langFile) => {
console.log("LOAD LANGUAGE " + lang)
// we store agnostically the last selected language as default, if no user is logged in.
window.localStorage.setItem(
Meteor.settings.public.brand + "_lang",
lang
)
loadedLanguages.push(lang)
if (langFile) {
i18n.setLocaleMessage(lang, Object.assign(langFile))
}
i18n.locale = lang
return lang
}
export const loadLanguageModule = (lang, langFile) => {
console.log("LOAD LANGUAGE MODULE" + lang)
i18n.mergeLocaleMessage(lang, Object.assign(langFile))
return lang
}
export function loadLanguageAsync(lang) {
if (i18n.locale !== lang) {
if (!loadedLanguages.includes(lang)) {
switch (lang) {
case "en":
return import("./lang/en.json").then(langFile => loadLanguage("en", langFile))
case "fr":
return import("./lang/fr.json").then(langFile => loadLanguage("fr", langFile))
default:
return import("./lang/fr.json").then(langFile => loadLanguage("fr", langFile))
}
} else {
console.log("Already loaded " + lang)
}
return Promise.resolve(!loadedLanguages.includes(lang) || loadLanguage(lang))
}
return Promise.resolve(lang)
}
Загрузка языка пользовательского модуля
const userLoadedLanguages = []
export default function loadUserLanguageAsync(lang) {
if (i18n.locale !== lang || !userLoadedLanguages.includes(lang)) {
switch (lang) {
case "en":
return import("./lang/en.json").then(langFile => loadLanguageModule("en", langFile))
case "fr":
return import("./lang/fr.json").then(langFile => loadLanguageModule("fr", langFile))
default:
return import("./lang/fr.json").then(langFile => loadLanguageModule("fr", langFile))
}
}
return Promise.resolve(i18n.messages[lang].user).then(console.log("USER LANG LOADED"))
}
- После загрузки каждого модуля я устанавливаю флажок, который позволяет моему навигационному устройству маршрутизатора переходить к требуемому маршруту (см.основная загружаемая часть).
Асинхронная функция защиты маршрутизатора и ожидания
router.beforeEach((to, from, next) => {
isReady().then(
console.log("NEXT"),
next()
)
})
async function isReady() {
while (true) {
if (this.modulesReady) { console.log("READY"); return }
await null // prevents app from hanging
}
}
Я совершенно новичок в логике асинхронности и пытаюсь определитьчто я делаю не такПриведенный здесь код приводит к сбою браузера, так как я предполагаю, что значения моих обещаний не правильные, и он идет в бесконечном цикле isReady()
.
Я бы очень хотел получить предложения или советы по поводу лучшего / правильного способаидти.Кроме того, не стесняйтесь запрашивать более подробную информацию, если чего-то не хватает.
Спасибо!