[英]Using a Promise inside of a forEach loop
I am new to using Promise
and cannot quite get this right. 我是使用
Promise
新手,并不能完全正确。
I am trying to create a situation where I load the google maps API script if an element on the page requires it. 我试图创建一种情况,我加载谷歌地图API脚本,如果页面上的元素需要它。 This part I have got working, what I am struggling with is if there are more than 1 elements on the page that requires google maps API I need to only load the script once.
这部分我已经开始工作,我正在努力的是,如果页面上有超过1个元素需要谷歌地图API,我只需要加载一次脚本。
Here is what I have so far. 这是我到目前为止所拥有的。
index.html 的index.html
<div class="map" id="map-1" data-module="map" style="height: 100vh;"></div>
<div class="map" id="map-2" data-module="map" style="height: 100vh;"></div>
<div class="map" id="map-3" data-module="map" style="height: 100vh;"></div>
<div class="map" id="map-4" data-module="map" style="height: 100vh;"></div>
loadGoogleMapsApi.js loadGoogleMapsApi.js
export default class LoadGoogleMapsAPI {
constructor() {
this.apiKey = '********';
// set a globally scoped callback if it doesn't already exist
/* eslint no-underscore-dangle: 0 */
if (!window._GoogleMapsApi) {
this.callbackName = '_GoogleMapsApi.mapLoaded';
window._GoogleMapsApi = this;
window._GoogleMapsApi.mapLoaded = this.mapLoaded.bind(this);
}
}
/**
* Load the Google Maps API javascript
*/
async load() {
if (!this.promise) {
this.promise = await new Promise((resolve) => {
this.resolve = resolve;
if (typeof window.google === 'undefined') {
const script = document.createElement('script');
script.src = `//maps.googleapis.com/maps/api/js?key=${window._GoogleMapsApi.apiKey}&callback=${window._GoogleMapsApi.callbackName}`;
script.async = true;
document.body.append(script);
} else {
this.resolve();
}
});
}
return this.promise;
}
/**
* Globally scoped callback for the map loaded
*/
mapLoaded() {
if (this.resolve) {
this.resolve();
}
}
}
map.js map.js
import GoogleMapsApi from '../utils/loadGoogleMapsApi';
export default class MapViewModel {
constructor(module) {
this.module = module;
const gmapApi = new GoogleMapsApi();
gmapApi.load().then(() => {
// safe to start using the API now
new google.maps.Map(this.module, {
center: { lat: 51.5074, lng: -0.1278 },
zoom: 11,
});
// etc.
});
}
static init() {
const instances = document.querySelectorAll('[data-module="map"]');
instances.forEach((module) => {
const options = JSON.parse(module.getAttribute('data-map-settings'));
new MapViewModel(module, options);
});
}
}
MapViewModel.init();
The issue is in the load()
function (i think). 问题出在
load()
函数中(我认为)。 I have tried all sorts of different things and this is the closest I get. 我尝试过各种不同的东西,这是我得到的最接近的东西。 It seems that the code either does not wait and puts the script tag in 4 times OR the code resolves before the script tag has loaded and my
google.maps.Map(...)
doesn't work. 似乎代码要么不等待并将脚本标记放入4次,要么代码在脚本标记加载之前解析,并且我的
google.maps.Map(...)
不起作用。
Any help I can get will be greatly appreciated. 我将非常感谢您提供的任何帮助。
Cheers, Luke. 干杯,卢克。
UPDATE UPDATE
SOLVED 解决了
New code thanks to @jcubic helping me finally reach a solution. 感谢@jcubic的新代码帮助我最终找到了解决方案。
loadGoogleMapsApi.js loadGoogleMapsApi.js
export default class LoadGoogleMapsAPI {
/**
* Load the Google Maps API javascript
*/
static load() {
this.apiKey = '******';
if (!this.promise) {
this.promise = new Promise((resolve) => {
if (typeof window.google === 'undefined') {
const script = document.createElement('script');
script.onload = resolve;
script.src = `//maps.googleapis.com/maps/api/js?key=${this.apiKey}`;
script.async = true;
document.body.append(script);
}
});
}
return this.promise;
}
}
map.js map.js
import GoogleMapsApi from '../utils/loadGoogleMapsApi';
export default class MapViewModel {
constructor(module) {
this.module = module;
GoogleMapsApi.load().then(() => {
// safe to start using the API now
new google.maps.Map(this.module, {
center: { lat: 51.5074, lng: -0.1278 },
zoom: 11,
});
// etc.
});
}
static init() {
const instances = document.querySelectorAll('[data-module="map"]');
instances.forEach((module) => {
const options = JSON.parse(module.getAttribute('data-map-settings'));
new MapViewModel(module, options);
});
}
}
MapViewModel.init();
So the 2 parts to the solution are making loadGoogleMapsApi.js a static class and moving the constructor
code inside the load()
function. 因此解决方案的两个部分是使loadGoogleMapsApi.js成为一个静态类,并在
load()
函数中移动constructor
代码。 Then also changing the load()
function to not use async/await and adding script.onload = resolve
. 然后还将
load()
函数更改为不使用async / await并添加script.onload = resolve
。
If you use this this.promise = await new Promise((resolve) => {
this.promise will not be a promise but value that promise resolve to, this is how async/await works. You're resolving it with undefined (no value to resolve()) so this.promise
is undefined (it's always false). 如果你使用
this.promise = await new Promise((resolve) => {
this.promise将不是一个承诺但是承诺解决的值,这就是async / await的工作原理。你用unfined解决它(不是要解析的值())所以this.promise
是未定义的(它总是假的)。
EDIT you also need to call this.resolve otherwise if you call in a loop you execute it multiple times before it finish, you probably also want to resolve the promise when script will be ready: 编辑你还需要调用this.resolve否则如果你在一个循环中调用你在它完成之前多次执行它,你可能还想在脚本准备就绪时解决这个问题:
load() {
if (!this.promise) {
this.promise = new Promise((resolve) => {
if (typeof window.google === 'undefined') {
const script = document.createElement('script');
script.onload = resolve;
script.src = `//maps.googleapis.com/maps/api/js?key=${window._GoogleMapsApi.apiKey}&callback=${window._GoogleMapsApi.callbackName}`;
script.async = true;
document.body.append(script);
}
});
}
return this.promise;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.