'use strict'; /* * LabLoader — ленивый загрузчик кода симуляций (контент-движок, Фаза 3). * * Тяжёлый код симуляций (~2.5 МБ) и three.js (~600 КБ) больше НЕ грузятся на старте. * При открытии симуляции LabLoader.ensure(id) подгружает её файлы (по манифесту * window.SIM_DEPS из _sim_deps.js) и, при необходимости, three.js — затем резолвит. * * Гарантия корректности (самовосстановление): если после загрузки указанных файлов * глобальная open-функция (SIM_DEPS[id].open, напр. "_openPendulum") всё ещё не * определена, грузятся ВСЕ ленивые файлы (window.LAB_LAZY_FILES). Поэтому ошибка в * манифесте не может «сломать» симуляцию — в худшем случае грузится больше файлов * (поведение как до Фазы 3). Манифест лишь оптимизирует объём загрузки. * * Все загрузки кешируются (по URL) и дедуплицируются. */ (function () { var BASE = '/js/labs/'; var THREE_URL = 'https://cdn.jsdelivr.net/npm/three@0.149.0/build/three.min.js'; var _cache = {}; // url -> Promise var _allLoaded = false; function loadScript(url) { if (_cache[url]) return _cache[url]; _cache[url] = new Promise(function (resolve, reject) { var s = document.createElement('script'); s.src = url; s.async = false; // сохранить порядок при добавлении нескольких сразу s.onload = function () { resolve(url); }; s.onerror = function () { delete _cache[url]; reject(new Error('LabLoader: не удалось загрузить ' + url)); }; document.head.appendChild(s); }); return _cache[url]; } function ensureThree() { if (typeof window.THREE !== 'undefined') return Promise.resolve(); return loadScript(THREE_URL); } function loadFiles(files) { return Promise.all((files || []).map(function (f) { return loadScript(BASE + f); })); } function loadAllLazy() { if (_allLoaded) return Promise.resolve(); var list = window.LAB_LAZY_FILES || []; return loadFiles(list).then(function () { _allLoaded = true; }); } // ensure(id): загрузить всё необходимое для симуляции id, вернуть Promise. function ensure(id) { var dep = (window.SIM_DEPS && window.SIM_DEPS[id]) || null; if (!dep) { // нет манифеста для id — безопасно грузим всё return loadAllLazy(); } var p = dep.three ? ensureThree() : Promise.resolve(); return p .then(function () { return loadFiles(dep.files); }) .then(function () { var openName = dep.open; if (openName && typeof window[openName] !== 'function') { if (window.console) console.warn('[LabLoader] самовосстановление для "' + id + '": ' + openName + ' не найдена после загрузки ' + JSON.stringify(dep.files) + ' — гружу все ленивые файлы'); return loadAllLazy(); } }); } window.LabLoader = { ensure: ensure, ensureThree: ensureThree, loadScript: loadScript, loadAllLazy: loadAllLazy }; })();