简体   繁体   English

只有最后一个对象被推送到对象数组(JavaScript)

[英]Only last object is being pushed to object array (JavaScript)

I have a function which essentially creates an object and then pushes each newly created object to an array of objects.我有一个函数,它本质上创建一个对象,然后将每个新创建的对象推送到一个对象数组中。 However I am facing an issue where only the last object being created (in my for loop) is being pushed to my object array.但是我面临一个问题,即只有最后一个正在创建的对象(在我的 for 循环中)被推送到我的对象数组中。

I firstly declare my object and object array:我首先声明我的对象和对象数组:

this.locationObjectArray = [];
this.locationObject = {};

I then declare a variable "that" equal to "this" so that I can use the above declared object and object array in my callbacks:然后我声明一个等于“this”的变量“that”,这样我就可以在回调中使用上面声明的对象和对象数组:

var that = this;

I then read an odata entity which returns a success callback with the specified entities data:然后我读取了一个 odata 实体,它返回一个带有指定实体数据的成功回调:

oModel.read("/Customers", {
                success: function (resp) {
                    var promises = [];
                    for (var x = 0; x < resp.results.length; x++) {
                        // Set tooltip property
                        var tooltip = resp.results[x].Country;
                        that.locationObject.tooltip = tooltip;
                        // Set type property
                        that.locationObject.type = "Inactive";
                        // Set position property
                        var request = $.ajax({
                            url: "https://api.opencagedata.com/geocode/v1/json?key=d3e40bf9b50247d4acf8122c543c5187&q=" + tooltip,
                            type: "GET",
                            dataType: 'json',
                            success: function (resp) {
                                that.locationObject.pos = resp.results[0].geometry.lng + ";" + resp.results[0].geometry.lat + ";0";
                            }
                        });
                        // Populate promises and locationObjectArray     
                        that.locationObjectArray.push(that.locationObject);
                        promises.push(request);
                        console.log(that.locationObject);
                    }
                    $.when.apply(null, promises).done(function(){
                        // console.log(that.locationObjectArray);
                        that.getView().getModel("map").setProperty("/Spots", that.locationObjectArray);
                    })
                }
            })

I created an array called promises as in my for loop I am making an Ajax request to an API which will return a promise each time it loops.我创建了一个名为 Promise 的数组,因为在我的 for 循环中我正在向 API 发出 Ajax 请求,该 API 每次循环时都会返回一个 Promise。 I need to contain each request (promise) so that I can set the remainder of the function to run only once all of the data requested in each request (of each loop) is received.我需要包含每个请求(承诺),以便我可以将函数的其余部分设置为仅在收到每个请求(每个循环的)中请求的所有数据后才运行。

I then create my for loop.然后我创建我的 for 循环。

Within the for loop I begin to set each property of the previously declared "locationObject".在 for 循环中,我开始设置先前声明的“locationObject”的每个属性。 The properties are: "tooltip" (locationObject.tooltip), "type" (locationObject.type) and "pos" (locationObject.pos).属性为:“tooltip”(locationObject.tooltip)、“type”(locationObject.type)和“pos”(locationObject.pos)。 Both properties "tooltip" and "type" are straight forward. “工具提示”和“类型”这两个属性都是直截了当的。 It is only the property "pos" that is causing difficulties as this data is returned as the result of a promise success callback in each loop.只有属性“pos”会导致困难,因为此数据是作为每个循环中的 promise 成功回调的结果返回的。

Nevertheless, I then push the newly created object to the object array and also push that loops promise to the promises array.尽管如此,然后我将新创建的对象推送到对象数组,并将循环 promise 推送到 promises 数组。

Once the for loop has finished and all promises are resolved, I then set my data model.一旦 for 循环完成并解决了所有承诺,我就设置了我的数据模型。

The above would appear as fine, although the resulting object array (locationObjectArray) comes out like this:尽管结果对象数组 (locationObjectArray) 如下所示:

在此处输入图像描述

The entire array is populated (for each loop) with the data collected in the locationObject for the final loop.整个数组被填充(对于每个循环),其中包含在 locationObject 中为最终循环收集的数据。

I have attempted to reset the object (locationObject) at the beginning of each loop:我试图在每个循环开始时重置对象(locationObject):

...
for (var x = 0; x < resp.results.length; x++) {
    that.locationObject = {};
    ...

However that interferes with the Ajax request to get the "pos" property data for each object, and the resulting array is constructed successfully with only the "tooltip" and "type" properties set:但是,这会干扰 Ajax 请求以获取每个对象的“pos”属性数据,并且仅使用“tooltip”和“type”属性集成功构造了结果数组:

在此处输入图像描述

I am not sure what I could do to get around this, or why the promises are now ignored, any suggestions / advice will be appreciated.我不确定我能做些什么来解决这个问题,或者为什么现在忽略承诺,任何建议/建议将不胜感激。

There are several issues in this code.这段代码有几个问题。 The main one I see is that you only have one locationObject that you keep modifying and pushing into the array over and over again.我看到的主要是你只有一个locationObject ,你不断地修改并一次又一次地推入数组。 Since .push() pushes a reference to that object (does not make a copy), you just end up with an array of all the same object in it and it has the value from the last item that you processed.由于.push()推送对该对象的引用(不进行复制),因此您最终会得到一个包含所有相同对象的数组,并且它具有您处理的最后一项的值。

You can fix that main issue by just creating a new locationObject in your loop.您可以通过在循环中创建一个新的locationObject来解决该主要问题。 Here's what I would suggest for a rewrite:以下是我对重写的建议:

oModel.read("/Customers", {
    success: async function(resp) {
        for (let result of resp.results) {
            const locationObject = {};
            const tooltip = result.Country;
            locationObject.type = "Inactive";
            const geoData = await $.ajax({
                url: "https://api.opencagedata.com/geocode/v1/json?key=d3e40bf9b50247d4acf8122c543c5187&q=" + tooltip,
                type: "GET",
                dataType: 'json',
            });
            locationObject.pos = geoData.results[0].geometry.lng + ";" + geoData.results[0].geometry.lat + ";0";
            that.locationObjectArray.push(that.locationObject);
        }
        that.getView().getModel("map").setProperty("/Spots", that.locationObjectArray);
    }
});

This uses the promise that $.ajax() returns and gets rid of the success callback for $.ajax() .这使用了$.ajax()返回的承诺并摆脱了$.ajax()success回调。 It also simplifies the code by serializing the for loop with await .它还通过使用await序列化for循环来简化代码。


If you want to run all the ajax calls in parallel and avoid using await , you can do it this way:如果您想并行运行所有 ajax 调用并避免使用await ,您可以这样做:

oModel.read("/Customers", {
    success: function(resp) {
        Promise.all(resp.results.map(result => {
            const locationObject = {};
            const tooltip = result.Country;
            locationObject.type = "Inactive";
            return $.ajax({
                url: "https://api.opencagedata.com/geocode/v1/json?key=d3e40bf9b50247d4acf8122c543c5187&q=" + tooltip,
                type: "GET",
                dataType: 'json',
            }).then(geoData => {
                locationObject.pos = geoData.results[0].geometry.lng + ";" + geoData.results[0].geometry.lat + ";0";
                return locationObject;
            });
        })).then((locationArray) => {
            that.getView().getModel("map").setProperty("/Spots", locationObjectArray);
        });
    }
});

Note, this avoids using that.locationObject and that.locationObjectArray entirely.请注意,这完全避免了使用that.locationObjectthat.locationObjectArray The results are collected and used internally without those higher scoped variables.结果在没有那些更高范围的变量的情况下在内部收集和使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM