Griffin Burns Griffin Burns - 20 days ago 6
Javascript Question

Javascript: Promise not working. .then executing before resolve completes

First time working with promises. I'm working with the google maps api to drop markers with setTimeout delays between markers and then clustering the markers. I have two promises. one to resolve the individual marker object from a location, and then another promise to return the array of marker objects for clustering purposes. In the console i'm seeing the dump of

console.log('markers before clustering');
before i'm seeing
console.log('iteration: [' + timeout + '] value: [' + value +']');
which tells me
.then
is executing before
resolve
returns something.

In my code,
markers
is a blank variable and
locations
is a lat/lng object that is pre-defined.

Here is the console output:

markers before clustering

maps.js:52 [undefined, undefined, undefined, undefined]

maps.js:77 markers after callback

maps.js:78 [undefined, undefined, undefined, undefined]

maps.js:69 iteration: [0] value: [[object Object]]

maps.js:69 iteration: [1] value: [[object Object]]

maps.js:69 iteration: [2] value: [[object Object]]

maps.js:69 iteration: [3] value: [[object Object]]


CODE:

function dropMarkers(markers) {
//locations are passed in from php json. variable is defined/populated prior to this .js file.
let test = new Promise(function(resolve, reject) {
markers = locations.map(addMarkerWithTimeout);

resolve(markers);
});

test.then(function(value){
console.log('markers before clustering');

//console dump is showing that markers are being populated correctly. I believe the problem is with the .push method above
console.log(value);
clustering(value);
});
}


function addMarkerWithTimeout(position, timeout) {
let prom = new Promise(function(resolve, reject) {
window.setTimeout(function(){
resolve(new google.maps.Marker({
position: position,
map: map,
animation: google.maps.Animation.DROP}));
}, timeout*300);
});

prom.then(function(value) {
console.log('iteration: [' + timeout + '] value: [' + value +']');
return value;
});
}


//add a marker clusterer to manage the markers.
function clustering(markers) {
console.log('markers after callback');
console.log(markers);

markerCluster = new MarkerClusterer(map, markers, {
imagePath: 'images/m'});
}

Answer

In dropMarkers, you want to wait for all the markers to resolve - for this, Promise.all is the weapon of choice:

function dropMarkers(markers) {
    //locations are passed in from php json.  variable is defined/populated prior to this .js file.
    Promise.all(locations.map(addMarkerWithTimeout))
    .then(function(value){
        console.log('markers before clustering');

        //console dump is showing that markers are being populated correctly.  I believe the problem is with the .push method above
        console.log(value);
        clustering(value);
    });
}

If you are calling dropMarkers, and want to "wait" on the completion, simply return Promise.all ... and use

dropMarkers([]).then( ...

In addMarkerWithTimeout - you want to return a Promise

function addMarkerWithTimeout(position, timeout) {
    return new Promise(function(resolve, reject) {
        window.setTimeout(function(){
            resolve(new google.maps.Marker({
                position: position,
                map: map,
                animation: google.maps.Animation.DROP
            }));
        }, timeout*300);
    })
    .then(function(value) {
        console.log('iteration: [' + timeout + '] value: [' + value +']');
        return value;
    });
}

I hope this helps

Comments