【问题标题】:AngularJS Promise. undefined array that existsAngularJS 承诺。存在的未定义数组
【发布时间】:2017-11-14 05:59:33
【问题描述】:

所以我正在做一些promise 链,因为我需要一些同步运行的代码。在我有两个嵌套的forEach 之前一切都很好。在第一个forEach 之后,我显示了具有我要迭代的下一个数组的实际对象。在那儿!但是后来我尝试迭代那个数组并且是undefined?

vm.enviarEmail = function() {
    var result = {};
    var def = $q.defer();
    def.promise
    .then(function(result){
        console.log("1");
        return estacion.leerEstacionesInforiego()
        .then(function(respuesta) {
            angular.forEach(respuesta, function(est) {
                est.latitud = $rootScope.dmsToddI(est.latitud);
                est.longitud = $rootScope.dmsToddI(est.longitud);
            });
            result.estaciones = respuesta;
            console.log("estaciones",result.estaciones);
            return result;
        }, function(respuesta) {
            console.log("ERROR: obtención de las estaciones no realizada");
        });
        return result;
    })
    .then(function(result) {
        console.log("2");
        return user.leerUsuarios()
        .then(function(respuesta) {
            result.users = respuesta;
            console.log("usuarios",result.users);
            return result;
        }, function(respuesta) {
            console.log("ERROR: obtención de usuarios no realizada.");
        });
        return result;
    })
    .then(function(result) {
        console.log("3");
        angular.forEach(result.users, function(user) {
            user.html = "<style>td {border:solid 1px;}</style><table><thead><tr><th>Parcela</th><th>Estación</th><th>Cultivo</th><th>Método de riego</th>"+
            "<th>Fecha siembra</th><th>Fecha último riego</th><th>Recomendación</th></tr></thead><tbody>";
            campo.leerParcelasPropietario(user.id)
            .then(function(respuesta) {
                user.parcelas = respuesta;
            }, function(respuesta) {
                console.log("ERROR: obtención de parcelas por usuario no realizada.");
            });
        });
        console.log("parcelas",result);
        return result;
    })
    .then(function(result) {
        console.log("4");
        angular.forEach(result.users, function(user) {
            console.log(user,user.parcelas);
            angular.forEach(user.parcelas, function(par) {
                console.log("parcela",par.nombre);
                var hoy = new Date();                           // Fecha actual
                
                // Obtener el cultivo de la parcela
                campo.leerCultivo(par.cultivo)
                .then(function(respuesta) {
                    par.cultivo = respuesta;
                    console.log(par);
                }, function(respuesta) {
                    console.log("ERROR: obtención del cultivo no realizada");
                });
                
                // Obtener el método de riego de la parcela
                campo.leerMetodoRiego(par.riego)
                .then(function(respuesta) {
                    par.riego = respuesta;
                }, function(respuesta) {
                    console.log("ERROR: obtención del método de riego no realizada");
                });
                
                // Calcular la estación cercana
                var distMin = 99999999;
                var x1 = new google.maps.LatLng(par.latitud,par.longitud);
                angular.forEach(result.estaciones, function(est) {
                    var x2 = new google.maps.LatLng(est.latitud,est.longitud);
                    var distancia = google.maps.geometry.spherical.computeDistanceBetween(x1, x2);
                    if (distancia < distMin) {
                        distMin = distancia;
                        par.estacion = est;
                    }
                });
                
                // Cálculo de días desde el último riego
                var fecha = new Date(Date.parse(par.consulta));
                par.diasR = (hoy - fecha)/(1000*60*60*24);  // En días y no milisegundos
                    
                // Cálculo del estado del cultivo
                var fechaS = new Date(Date.parse(par.siembra));
                par.diasE = (hoy - fechaS)/(1000*60*60*24);

                if (par.diasE < 46)
                    par.estado = 'ini';
                else if (par.diasE < 76)
                    par.estado = 'des';
                else if (par.diasE < 96)
                    par.estado = 'med';
                else
                    par.estado = 'fin';
            });
        });
        return result;
    })
    .then(function(result) {
        console.log("5");
        angular.forEach(result.users, function(user) {
            console.log("para obtener datos",result.users);
            angular.forEach(user.parcelas, function(par) {
                estacion.obtenerDatosInforiego(Math.round(par.diasR),par.estacion.indicativo,par.estacion.provincia)
                .then(function(respuesta) {
                    par.datos = respuesta;                      
                }, function(respuesta) {
                    console.log("ERROR: obtención de los datos de Inforiego no realizada");
                });
            });
        });
        return result;              
    })
    .then(function(result) {
        console.log("6");
        angular.forEach(result.users, function(user) {
            angular.forEach(user.parcelas, function(par) {
                par.datos_totales = {et0: 0, etc: 0, pe: 0};    // Los datos totales obtenidos de los cálculos
                angular.forEach(par.datos, function(diadatos) {
                    // Corrección de la temperatura media
                    diadatos.tempmedia = (diadatos.tempmax+diadatos.tempmin)/2;
                    
                    // Cálculo de la presión atmosférica (kPa)
                    diadatos.presion = 101.3*Math.pow(((293-(0.0065*par.estacion.altitud))/293),5.26);
                    
                    // Cálculo de la constante psicométrica (kPa/ºC)
                    diadatos.constante_psicometrica = diadatos.presion*0.000665;
                    
                    // Cálculo de la presión de saturación de vapor a la temperatura del aire (max, med y min) (kPa)
                    var psvmax = 0.6108*Math.pow(2.7183,(17.27*diadatos.tempmax)/(diadatos.tempmax+237.3));
                    var psvmin = 0.6108*Math.pow(2.7183,(17.27*diadatos.tempmin)/(diadatos.tempmin+237.3));
                    var psvmed = (psvmax+psvmin)/2;
                    
                    // Cálculo de la presión real de vapor (kPa)
                    diadatos.presion_real_vapor = (psvmed*diadatos.humedadmedia)/100;
                    
                    // Cálculo de la pendiente de la curva de presión de vapor (kPa/ºC)
                    diadatos.pendiente_curva_presion = (4098*psvmed)/Math.pow((diadatos.tempmedia+237.3),2);
                    
                    // Cálculo de la ET0
                    diadatos.et0 = ((0.408*diadatos.pendiente_curva_presion*diadatos.rn)
                            +(diadatos.constante_psicometrica*diadatos.velviento*900*(psvmed-diadatos.presion_real_vapor))/(273+diadatos.tempmedia))
                            /(diadatos.pendiente_curva_presion+(diadatos.constante_psicometrica*(1+0.34*diadatos.velviento)));
                    
                    // Cálculo de la ETc
                    if (par.estado == 'ini') {
                        diadatos.etc = diadatos.et0*par.cultivo.coef_ini;
                        diadatos.kc = par.cultivo.coef_ini;
                    } else if (par.estado == 'des') {
                        diadatos.etc = diadatos.et0*par.cultivo.coef_des;
                        diadatos.kc = par.cultivo.coef_des;
                    } else if (par.estado == 'med') {
                        diadatos.etc = diadatos.et0*par.cultivo.coef_med;
                        diadatos.kc = par.cultivo.coef_med;
                    } else if (par.estado == 'fin') {
                        diadatos.etc = diadatos.et0*par.cultivo.coef_fin;
                        diadatos.kc = par.cultivo.coef_fin;
                    }
                    
                    // Sumar para los totales
                    par.datos_totales.et0 = par.datos_totales.et0 + diadatos.et0;
                    par.datos_totales.etc = par.datos_totales.etc + diadatos.etc;
                    par.datos_totales.pe = par.datos_totales.pe + diadatos.pepmon;
                });
                par.datos_totales.rr = (par.datos_totales.etc-par.datos_totales.pe)/par.riego.coef_eficiencia;
                user.html = user.html + "<tr><td>" + par.nombre + "</td><td>" + par.estacion.nombre + "</td>"+
                "<td>" + par.cultivo.nombre + "</td><td>" + par.riego.nombre + "</td>"+
                "<td>" + $filter('date')(par.siembra, 'dd-MM-yyyy') + "</td>"+
                "<td>" + $filter('date')(par.consulta, 'dd-MM-yyyy') + "</td>"+
                "<td><b>" + Math.round(par.datos_totales.rr) + "</b> l/m<sup>2</sup></td></tr>";
            });
        });
        return result;
    })
    .then(function(result) {
        console.log("7");
        angular.forEach(result.users, function(user) {
            if (user.usuario != 'jlmm') {
                user.html = user.html + "</tbody></table><br><a href='http://localhost:8080/AgriWea/#!/'>AgriWea</a>";
                $http.post('http://localhost:8100/sendmail', {params: {
                      from: 'AgriWea <jmariscan@dominio.es>',
                      to: user.email,
                      subject: 'Recomendación diaria de riego',
                      html: user.html}})
                .then(function(respuesta) {
                    console.log("Email enviado correctamente",texto);
                }, function(respuesta) {
                    console.log("Email no enviado", respuesta);
                });
            }
        });
    })
    .catch(function (error) {
        console.log(error);
    });
    def.resolve(result);

如您所见,我有一个console.log,这就是我得到的:

我在想也许对象是 undefined 因为 Angular 中的异步但在同一个 console.log 我可以看到该数组存在但如果我尝试访问它是 undefined。救命!

解决方案

使用@trincot 的代码,我减少了then 的数量,并且只用了三个代码。谢谢大家!

【问题讨论】:

  • 您是否在另一个then(..)s 中为result.users 分配了任何东西?剩下的可以分享一下吗?
  • 尝试将 debugger; 放入 forEach 并逐步查看会发生什么
  • 作为一个提示,我可以告诉你我和你的情况一样,但是控制台日志欺骗了我,这确实是异步设置值晚于访问代码的问题。我认为控制台日志是在您的循环之后执行的,尽管在您的代码中它是之前编写的。请检查您的回调并确保之前的每个回调都成功。
  • @NikolajDamLarsen 里面有函数的所有代码..太多了呵呵。

标签: javascript arrays angularjs promise


【解决方案1】:

您声明您使用承诺链是因为您希望同步运行代码,但这是不可能的。承诺链的各个部分是异步执行的。函数中的最后一行在任何 then 回调之前执行。

此外,您不能指望函数调用会返回电子邮件。目前,您的函数没有返回任何内容,因此当您调用该函数时,您将获得undefined

但即使你会返回一些东西,它也永远不会是结果。最多可以返回一个承诺。

您需要接受异步行为,并继续使用该模式。所以不要指望同步赋值。相反,请继续使用then

例如,您可以从一个立即解决的 Promise 开始,将空结果对象沿链传递:

vm.enviarEmail = function() {
  $q.when({}).then(function(result) {
      ...
      return result; // <-- don't forget to return the enriched value
    })
    .then(function(result) {
      ...
      return result; 
    })
    .then(function(result) {
      ...
      return result; 
    })
    .then(function(result) {
      angular.forEach(result.users, function(user) {
        console.log(user, user.parcelas);
        angular.forEach(user.parcelas, function(par) {
          ...
        });
      });
      return result; // <-- you need to return the promise    
    });
};

那你按如下方式使用:

vm.enviarEmail().then(function (result)  {
     console.log(result); // keep with the async pattern
});

【讨论】:

  • vm.enviarEmail 是函数的名称,我不返回任何内容,因为我的函数中没有任何内容要返回。我知道then 中的代码是异步的,但forEach 是同步的,我不明白为什么在同一个console.log 中,用户有“parcelas”,但是当我尝试显示它们时是undefined... .
  • 确实,我更新了答案以考虑到该功能。但我看到你已经扩展了你的问题。您在 forEach 回调中有一个 return。请注意,您在forEach 中返回的任何内容都将无处可去。
  • 另外,嵌套 promise 也是个坏主意。 Promise 的优点之一是可以避免这种嵌套。代替forEach 循环,使用map 并将返回的数组提供给$q.when,并返回您从主promise 链中获得的promise。您的代码太长,无法将所有内容转换为正确的答案,但请研究一下,我相信您将能够清理您的代码。
  • 这是我第一次使用大型 Angular 项目,也是第一次使用 Promise。感谢returnforEach 的建议。我不明白你对map$q.when 所说的抱歉……我会尽力做到的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-07
  • 2023-03-17
  • 2018-01-17
  • 2018-12-06
相关资源
最近更新 更多