Последовательная загрузка скриптов с помощью Promises - PullRequest
0 голосов
/ 05 сентября 2018

Я пытаюсь загрузить Here Maps JS-скрипты, используя Promises. У меня есть три сценария, и последние два зависят от первого и могут быть загружены асинхронно после загрузки первого. Проблема в том, что после загрузки первого скрипта функция не ждет в then () :

const libraries = {
    mapsjsCore: 'http://js.api.here.com/v3/3.0/mapsjs-core.js',
    mapsjsService: 'http://js.api.here.com/v3/3.0/mapsjs-service.js',
    mapjsEvents: 'http://js.api.here.com/v3/3.0/mapsjs-mapevents.js'
};

const headTag = document.getElementsByTagName('head')[0];

export const loadMap = function () {

    // First script loads, returns immediately and
    // starts initializing the map without
    // waiting the last two scripts to load ???
    
    return getLibrary(libraries.mapsjsCore)
    .then(() => Promise.all([
    
            // Load the rest async
            getLibrary(libraries.mapsjsService),
            getLibrary(libraries.mapjsEvents)
        ])
    )
    .catch(error => new Error('Unable to load map files'))
}

function getLibrary(url) {
    return new Promise((resolve, reject) => {
        let scriptHTML = document.createElement('script');

        scriptHTML.type = 'text/javascript';
        scriptHTML.charset = 'utf-8';
        scriptHTML.async = true;
        scriptHTML.src = url;

        scriptHTML.onload = function () {
            resolve(url);
        }
        scriptHTML.onerror = function () {
            reject('error')
        }

        headTag.appendChild(scriptHTML);
    })
}

Последовательность загрузки выглядит нормально:

loading sequence screenshot

Итак, как заставить loadMap () ожидать then () и затем возвращаться? Даже если я оберну loadMap () в Promise и разрешу после then () , результат будет таким же? Что мне здесь не хватает?

1 Ответ

0 голосов
/ 05 сентября 2018

Судя по вашим комментариям выше, похоже, что вы пытались:

loadMap().then(initMap());

Но проблема здесь в том, что initMap() выполнится немедленно. Вы должны использовать следующий синтаксис:

loadMap().then(initMap);

Функция initMap будет выполняться только после загрузки всех карт.

Ниже приведен полный рабочий пример.

const libraries = {
    mapsjsCore: 'http://js.api.here.com/v3/3.0/mapsjs-core.js',
    mapsjsService: 'http://js.api.here.com/v3/3.0/mapsjs-service.js',
    mapjsEvents: 'http://js.api.here.com/v3/3.0/mapsjs-mapevents.js'
};

const headTag = document.getElementsByTagName('head')[0];

const loadMap = function () {

    // First script loads, returns immediately and
    // starts initializing the map without
    // waiting the last two scripts to load ???
    
    return getLibrary(libraries.mapsjsCore)
    .then(() => Promise.all([
    
            // Load the rest async
            getLibrary(libraries.mapsjsService),
            getLibrary(libraries.mapjsEvents)
        ])
    )
    .catch(error => new Error('Unable to load map files'))
}

function getLibrary(url) {
    return new Promise((resolve, reject) => {
        let scriptHTML = document.createElement('script');

        scriptHTML.type = 'text/javascript';
        scriptHTML.charset = 'utf-8';
        scriptHTML.async = true;
        scriptHTML.src = url;

        scriptHTML.onload = function () {
            console.log(`Loaded: ${url}`);
            resolve(url);
        }
        scriptHTML.onerror = function () {
            reject('error')
        }

        headTag.appendChild(scriptHTML);
    })
}

function initMap() {
  console.log(`initMap`);
}

loadMap().then(initMap);
// This prints
//   Loaded: http://js.api.here.com/v3/3.0/mapsjs-core.js
//   Loaded: http://js.api.here.com/v3/3.0/mapsjs-service.js
//   Loaded: http://js.api.here.com/v3/3.0/mapsjs-mapevents.js
//   initMap
...