需要帮助创建带回调的异步函数

时间:2022-05-02 01:55:38

I have a JSON object with some entries (Appointments) each thereof an "location id". Then I loop trough these entries and emit a request to my nodeJS server by socketIO to get data from document with the location id.

我有一个JSON对象,其中一些条目(约会)每个都是“位置ID”。然后我循环这些条目并通过socketIO向我的nodeJS服务器发出请求,以从具有位置id的文档中获取数据。

At the end I need an array with the data of lat/lng to create some marker on a map.

最后,我需要一个带有lat / lng数据的数组,以在地图上创建一些标记。

Here is the code:

这是代码:

//controller for showing map
.controller('MapCtrl', function($scope, socket){

    socket.emit('getApp', staticUserid);

        socket.on('getApps', function (appdata) {
                var locArr = [];
                for (var i = 0; i < appdata.length; i++) {
                    if (appdata[i].locationid != '') {
                        locArr.push(appdata[i].locationid);
                    }
                }
                var LatLngArr = [];
                for (var j = 0; j < locArr.length; j++) {
                    socket.emit('getLocation', locArr[j]);
                    socket.on('getLoc', function (locData) {
                        console.log('received lat/lng: ' + locData.lat + '/' + locData.lng);
                        if (!LatLngArr[j]) LatLngArr[j] = []
                        LatLngArr[j][0] = locData.lat;
                        LatLngArr[j][1] = locData.lng;
                    });
                }
                //console.log('test:'+LatLngArr[0][0]);
        });

    var newMarkers = [[52.549678, 13.3879516],[52.5442992, 13.352809],[52.5186283,13.3761181]]; // this should be the generated array
    var newCenter = [52.549678, 13.3879516];
    createMap(newCenter,newMarkers);

})

The problem is, that the var LatLngArr isn't defined out of the...

问题是,var LatLngArr没有被定义出...

socket.on('getLoc', function (locData)

It would be very nice if somebody can help me :-)

如果有人可以帮助我,那将是非常好的:-)

Thanks so much!

非常感谢!

3 个解决方案

#1


1  

If you can use Promises

如果你可以使用Promises

.controller('MapCtrl', function($scope, socket){

    socket.emit('getApp', staticUserid);

    socket.on('getApps', function (appdata) {
        var locArr = [];
        for (var i = 0; i < appdata.length; i++) {
            if (appdata[i].locationid != '') {
                locArr.push(appdata[i].locationid);
            }
        }
        var LatLngArr = [];
        var promises = [];
        for (var j = 0; j < locArr.length; j++) {
            promises[j] = (function(captured_j) {
                return new Promise(function(resolve, reject) {
                    socket.emit('getLocation', locArr[captured_j]);
                    socket.on('getLoc', function (locData) {
                        console.log('received lat/lng: ' + locData.lat + '/' + locData.lng);
                        if (!LatLngArr[captured_j]) LatLngArr[captured_j] = []
                        LatLngArr[captured_j][0] = locData.lat;
                        LatLngArr[captured_j][1] = locData.lng;
                        resolve({index: captured_j, result: LatLngArr[captured_j]});
                    });
                });
            }(j));
        }
        Promise.all(promises).then(function(arr) {
            // ******************************************
            // ******************************************
            // arr is an array of {index: #, result [lat, lng]} - but you can also use LatLngArr
            // ******************************************
            // ******************************************
        });
    });
    var newMarkers = [[52.549678, 13.3879516],[52.5442992, 13.352809],[52.5186283,13.3761181]]; // this should be the generated array
    var newCenter = [52.549678, 13.3879516];
    createMap(newCenter,newMarkers);
})

#2


0  

try this

for (var j = 0; j < locArr.length; j++) {
    (function(captured_j) {
        socket.emit('getLocation', locArr[captured_j]);
        socket.on('getLoc', function (locData) {
            console.log('received lat/lng: ' + locData.lat + '/' + locData.lng);
            if (!LatLngArr[captured_j]) LatLngArr[captured_j] = []
            LatLngArr[captured_j][0] = locData.lat;
            LatLngArr[captured_j][1] = locData.lng;
            //
            // the required result
            //
            if (j === 0) {
                console.log('test:'+LatLngArr[0][0]);
            }
            //
        });
    }(j));
}

#3


0  

The reason why your code fails is because of the asynchronous nature of the line:

您的代码失败的原因是由于该行的异步性质:

socket.on('getLoc', function (locData)

So LatLngArr actually is defined when you register the callback, but it is not anymore at the time the callback is called. The reason for that is that JavaScript uses Closures.

因此LatLngArr实际上是在注册回调时定义的,但在调用回调时它不再是。原因是JavaScript使用Closures。

You may have a look at this thread: How do JavaScript closures work?

您可以查看此主题:JavaScript闭包如何工作?

Hence you have to wrap it in an IIFE. This way the function is executed immediately such that the value of j behaves as you intended, because it is not longer referring to the j of the outer scope.

因此,你必须把它包装在IIFE中。这样,函数立即执行,使得j的值按预期运行,因为它不再引用外部范围的j。

Edit: A very nice explanation can be found in Item 13 of David Hermann's "Effective Javascript" – a book I totally can recommend. If you have problems understanding it, a look at this thread may help.

编辑:一个非常好的解释可以在David Hermann的“有效Javascript”的第13项中找到 - 我完全可以推荐这本书。如果您在理解它时遇到问题,请查看此主题可能有所帮助。

#1


1  

If you can use Promises

如果你可以使用Promises

.controller('MapCtrl', function($scope, socket){

    socket.emit('getApp', staticUserid);

    socket.on('getApps', function (appdata) {
        var locArr = [];
        for (var i = 0; i < appdata.length; i++) {
            if (appdata[i].locationid != '') {
                locArr.push(appdata[i].locationid);
            }
        }
        var LatLngArr = [];
        var promises = [];
        for (var j = 0; j < locArr.length; j++) {
            promises[j] = (function(captured_j) {
                return new Promise(function(resolve, reject) {
                    socket.emit('getLocation', locArr[captured_j]);
                    socket.on('getLoc', function (locData) {
                        console.log('received lat/lng: ' + locData.lat + '/' + locData.lng);
                        if (!LatLngArr[captured_j]) LatLngArr[captured_j] = []
                        LatLngArr[captured_j][0] = locData.lat;
                        LatLngArr[captured_j][1] = locData.lng;
                        resolve({index: captured_j, result: LatLngArr[captured_j]});
                    });
                });
            }(j));
        }
        Promise.all(promises).then(function(arr) {
            // ******************************************
            // ******************************************
            // arr is an array of {index: #, result [lat, lng]} - but you can also use LatLngArr
            // ******************************************
            // ******************************************
        });
    });
    var newMarkers = [[52.549678, 13.3879516],[52.5442992, 13.352809],[52.5186283,13.3761181]]; // this should be the generated array
    var newCenter = [52.549678, 13.3879516];
    createMap(newCenter,newMarkers);
})

#2


0  

try this

for (var j = 0; j < locArr.length; j++) {
    (function(captured_j) {
        socket.emit('getLocation', locArr[captured_j]);
        socket.on('getLoc', function (locData) {
            console.log('received lat/lng: ' + locData.lat + '/' + locData.lng);
            if (!LatLngArr[captured_j]) LatLngArr[captured_j] = []
            LatLngArr[captured_j][0] = locData.lat;
            LatLngArr[captured_j][1] = locData.lng;
            //
            // the required result
            //
            if (j === 0) {
                console.log('test:'+LatLngArr[0][0]);
            }
            //
        });
    }(j));
}

#3


0  

The reason why your code fails is because of the asynchronous nature of the line:

您的代码失败的原因是由于该行的异步性质:

socket.on('getLoc', function (locData)

So LatLngArr actually is defined when you register the callback, but it is not anymore at the time the callback is called. The reason for that is that JavaScript uses Closures.

因此LatLngArr实际上是在注册回调时定义的,但在调用回调时它不再是。原因是JavaScript使用Closures。

You may have a look at this thread: How do JavaScript closures work?

您可以查看此主题:JavaScript闭包如何工作?

Hence you have to wrap it in an IIFE. This way the function is executed immediately such that the value of j behaves as you intended, because it is not longer referring to the j of the outer scope.

因此,你必须把它包装在IIFE中。这样,函数立即执行,使得j的值按预期运行,因为它不再引用外部范围的j。

Edit: A very nice explanation can be found in Item 13 of David Hermann's "Effective Javascript" – a book I totally can recommend. If you have problems understanding it, a look at this thread may help.

编辑:一个非常好的解释可以在David Hermann的“有效Javascript”的第13项中找到 - 我完全可以推荐这本书。如果您在理解它时遇到问题,请查看此主题可能有所帮助。