How can I return the value of a deferred method in javascript

1.8k views Asked by At

I am trying to write a module which projects coordinates into a new Spatial Reference, but the javascript syntax has beaten me once again.

This is how the module currently looks like:

define(["esri/geometry/Point", ...], 
    function(Point, SpatialReference, ...){

    var gmsvc = new GeometryService("http://server/maps/rest/services/Utilities/Geometry/GeometryServer");
    /*...*/

    return {
        /*...*/
        //transforms the current point on the map to the new wkid
        transformCoordinates: function(point, newWkId) {

            var param = new ProjectParameters();
            var newPoint;
            param.geometries = [point];
            param.outSR = new SpatialReference({ wkid: newWkId});

            gmsvc.project(param);

            gmsvc.on('project-complete', function(result) {
                newPoint = result.geometries[0];
            });

            return newPoint;
        }   
    };
});

As per the documentation GeometryService.project(parameter) is marked as deferred, so I try to access the result of it in the OnProjectComplete event. At this point result.geometries[0] is a valid Point with an x, y and SpatialReference property. Assigning this to the newPoint variable and returning it, results in an undefined being returned:

console.log(CoordinateTransUtils.transformCoordinates(evt.mapPoint, 5254));
> undefined

Changing the code to

return gmsvc.on('project-complete', function(result) {
    return result.geometries[0];
});

results in a return value of:

Object {id: 216, receiveArguments: true, previous: Object}advice: (){var b,c={},e=arguments.length;for(b=0;b<e;b++)c[f[b]]=arguments[b];c.target||(c.target=d);a.call(d,c)}id: 216next: Objectprevious: ObjectreceiveArguments: trueremove: (){if(h.advice){var c=h.previous,d=h.next;!d&&!c?delete b[e]:(c?c.next=d:b[e]=d,d&&(d.previous=c));b=a=h.advice=null}}__proto__: Object

which isn't a point either. My question therefore is, how to return the point stored in result.geometries[0] with an explanation what I am doing wrong here.

1

There are 1 answers

3
Ken Franqueiro On BEST ANSWER

In your example, newPoint will only actually set after the return statement is already processed, so it's undefined when that line runs.

Generally, if something within your function's logic is asynchronous, your function in itself will need to be asynchronous in nature as well. Typically in these cases it is recommended to return a promise. e.g.:

    transformCoordinates: function(point, newWkId) {
        var dfd = new Deferred(); // (from dojo/Deferred)
        var param = new ProjectParameters();
        param.geometries = [point];
        param.outSR = new SpatialReference({ wkid: newWkId});

        gmsvc.project(param);

        gmsvc.on('project-complete', function(result) {
            dfd.resolve(result.geometries[0]);
        });
        // If there is an accompanying error event, you should also
        // listen to that and call dfd.reject in its handler.

        return dfd.promise;
    }

See the Deferred and Promise tutorials for more information.