簡體   English   中英

在forEach循環中使用Promise

[英]Using a Promise inside of a forEach loop

我是使用Promise新手,並不能完全正確。

我試圖創建一種情況,我加載谷歌地圖API腳本,如果頁面上的元素需要它。 這部分我已經開始工作,我正在努力的是,如果頁面上有超過1個元素需要谷歌地圖API,我只需要加載一次腳本。

這是我到目前為止所擁有的。

的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

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

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();

問題出在load()函數中(我認為)。 我嘗試過各種不同的東西,這是我得到的最接近的東西。 似乎代碼要么不等待並將腳本標記放入4次,要么代碼在腳本標記加載之前解析,並且我的google.maps.Map(...)不起作用。

我將非常感謝您提供的任何幫助。

干杯,盧克。


UPDATE

解決了

感謝@jcubic的新代碼幫助我最終找到了解決方案。

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

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();

因此解決方案的兩個部分是使loadGoogleMapsApi.js成為一個靜態類,並在load()函數中移動constructor代碼。 然后還將load()函數更改為不使用async / await並添加script.onload = resolve

如果你使用this.promise = await new Promise((resolve) => { this.promise將不是一個承諾但是承諾解決的值,這就是async / await的工作原理。你用unfined解決它(不是要解析的值())所以this.promise是未定義的(它總是假的)。

編輯你還需要調用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM