使用 Promises 顺序加载脚本
Sequential Script Loading using Promises
我正在尝试使用 Promises 加载 Here Maps JS 脚本。我有三个脚本,最后两个依赖于第一个脚本,并且可以在第一个加载后异步加载。问题是第一个脚本加载后它不等待 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);
})
}
加载顺序似乎没问题:
那么如何让 loadMap() 等待 then() 然后 return?即使我将 loadMap() 包装在 Promise 中并在 then() 之后解析,结果是否相同?我在这里错过了什么?
根据您上面的评论,您似乎尝试过:
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
我正在尝试使用 Promises 加载 Here Maps JS 脚本。我有三个脚本,最后两个依赖于第一个脚本,并且可以在第一个加载后异步加载。问题是第一个脚本加载后它不等待 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);
})
}
加载顺序似乎没问题:
那么如何让 loadMap() 等待 then() 然后 return?即使我将 loadMap() 包装在 Promise 中并在 then() 之后解析,结果是否相同?我在这里错过了什么?
根据您上面的评论,您似乎尝试过:
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