使用 ionicLoading 和 AngularJS 执行步骤过程

Execute steps process using ionicLoading and AngularJS

我需要在我的控制器中执行一些步骤(加载时)。我想要本地 SQLite 数据库中的 select 数据,如果不存在,请在我的网络服务中发出请求。所有这些都带有加载指示器。我正在使用离子框架和 AngularJS.

我的实际代码没有显示进度并颠倒了检索数据的顺序(Empresas 之前的 Funcionarios)。

控制器:

$scope.$on('$ionicView.loaded', function () {
    $ionicLoading.show({
        template: 'loading'
    })

    //search in local database
    RepositorioEmpresas.obterTodos().then(function (empresas) {
        $scope.empresas = empresas;           

        if ($scope.empresas.length == 0) {
            //request to webservice
            ServicoEmpresas.obterEmpresas($rootScope.idSupervisor).then(function (response) {

                if (response.status == 1) {
                    $scope.empresas = response.dados;

                    //add data retrieve in local database
                    for (var i = 0; i < $scope.empresas.length; i++) {
                        RepositorioEmpresas.adicionar($scope.empresas[i]);
                    }                        
                }
            }, function (e) {
                Mensagem.alerta('error');
                $ionicLoading.hide();
            });
        }

        $rootScope.empresas = $scope.empresas;
    });

    //similar to the previous
    RepositorioFuncionarios.obterTodos().then(function (funcionarios) {
        var funcionariosTemp = funcionarios;            

        if (funcionariosTemp.length == 0) {
            ServicoFuncionarios.obterFuncionarios($rootScope.idSupervisor).then(function (response) {

                if (response.status == 1) {
                    funcionariosTemp = response.dados;

                    RepositorioFuncionarios.removerTodos();

                    for (var i = 0; i < funcionariosTemp.length; i++) {
                        RepositorioFuncionarios.adicionar(funcionariosTemp[i]);
                    }                       
                }
            }, function (e) {
                Mensagem.alerta('error.');
                $ionicLoading.hide();
            });
        }           
    });                    

    $ionicLoading.hide();
})

服务

.factory('ServicoFuncionarios', function ($http, $q) {
    const url = 'url';
    var self = this;
    var retorno = [];

    self.obterFuncionarios = function (idSupervisor) {
        var q = $q.defer();

        $http.get(url + '&idSupervisor=' + idSupervisor, { timeout: 5000 })
            .success(function (resposta) {
                q.resolve(resposta);
            })
            .error(function (e) {
                q.reject('erro na consulta ao webservice' + e);
            });

        return q.promise;
    }

    return self;
})

.factory('RepositorioFuncionarios', function (Repositorio) {
    var self = this;

    self.obterTodos = function () {
        return Repositorio.query("SELECT id, idEmpresa, nome, cpf FROM funcionarios")
            .then(function (resultado) {
                return Repositorio.obterTodos(resultado)
            });
    }

    self.adicionar = function (funcionario) {
        var campos = [funcionario.id, funcionario.idEmpresa, funcionario.nome, funcionario.cpf];
        return Repositorio.query("INSERT INTO funcionarios (id, idEmpresa, nome, cpf) VALUES (?,?,?,?)", campos);
    }

    self.removerTodos = function () {
        return Repositorio.query("DELETE FROM funcionarios");
    }

    return self;
})

代码已更新

优秀答案后,我调整了代码。仅当 RepositorioEmpresas 和 RepositorioFuncionarios 没有 return 数据时,我现在才需要执行 ServicoEmpresas 和 ServicoFuncionarios(在某些情况下,http 请求不是必需的)。我如何控制有条件的承诺?

$ionicLoading.show({
        content: 'Atualizando lista de usuários',
        animation: 'fade-in',
        showBackdrop: true,
        maxWidth: 200,
        showDelay: 0
    })

    RepositorioEmpresas.obterTodos().then(function (empresas) {
        $scope.empresas = empresas;
        console.log('Empresas carregadas!');

        if ($scope.empresas.length == 0) {
            return ServicoEmpresas.obterEmpresas($rootScope.idSupervisor)
        }

        $rootScope.empresas = $scope.empresas;
    }).then(function (response) {
        if (response.status == 1) {
            $scope.empresas = response.dados;

            RepositorioEmpresas.removerTodos();

            for (var i = 0; i < $scope.empresas.length; i++) {
                RepositorioEmpresas.adicionar($scope.empresas[i]);
            }
            console.log('Empresas consultadas!');

            $rootScope.empresas = $scope.empresas;
        }
    }).then(function () {
        return RepositorioFuncionarios.obterTodos();
    }).then(function (funcionarios) {
        var funcionariosTemp = funcionarios;
        console.log('Funcionários carregados!');

        if (funcionariosTemp.length == 0) {
            return ServicoFuncionarios.obterFuncionarios($rootScope.idSupervisor);
        }
    }).then(function (response) {
        if (response.status == 1) {
            funcionariosTemp = response.dados;

            RepositorioFuncionarios.removerTodos();

            for (var i = 0; i < funcionariosTemp.length; i++) {
                RepositorioFuncionarios.adicionar(funcionariosTemp[i]);
            }
            console.log('Funcionários consultados!');
        }
    }).catch(function (e) {
        Mensagem.alerta('Falha na consulta dos dados.');
    }).finally(function () {
        $ionicLoading.hide();
    })

你不是chaining那两个承诺。
它们是独立解决的,因此您无法保证哪个先于另一个执行。

$http 服务已经 return 是一个承诺,因此您可以避免这样做:

var q = $q.defer();

$http.get(url + '&idSupervisor=' + idSupervisor, { timeout: 5000 })
       .success(function (resposta) {
       q.resolve(resposta);
    })
    .error(function (e) {
       q.reject('erro na consulta ao webservice' + e);
    });

return q.promise;

但简单地说:

return $http.get(url + '&idSupervisor=' + idSupervisor, { timeout: 5000 });

$q 承诺使用 .then() 链接,如果它们是 resolved.catch() 如果有错误。

您的代码应执行如下操作:

RepositorioEmpresas.obterTodos()
    .then(function (empresas) {
        return ServicoEmpresas.obterEmpresas($rootScope.idSupervisor);
    })
    .then(function (response) {
        if (response.status == 1) {
            $scope.empresas = response.dados;

            //add data retrieve in local database
            for (var i = 0; i < $scope.empresas.length; i++) {
                RepositorioEmpresas.adicionar($scope.empresas[i]);
            }                        
                }       
    })
    .then(function (){
        return RepositorioFuncionarios.obterTodos();
    })
    .then(function (funcionarios){

    })
    .catch(function(reason() {
        // reason contains your error.
    });

正如你在每个 .then() 中看到的那样,我们调用一个 function/method 来解决一个承诺并使用 return 所以我们可以使用 returned 值(当承诺是决心)到下一个 .then():

.then(function (empresas) {
    return ServicoEmpresas.obterEmpresas($rootScope.idSupervisor);
})
.then(function (response) {
    // response is the returned value of ServicoEmpresas.obterEmpresas
})

您的操作方式也会导致 $ionicLoading 服务出现问题,因为您在最底部调用 $ionicLoading.hide();。此命令将在承诺执行之前立即执行,承诺将在 $http 服务 return 结果时解决。

您可以使用 .finally() 进行一些清理:

myPromise()
    .then(function (result) {
        return myOtherPromise();
    })
    .then(function (result) {
        // do something with the final result.
    })
    .catch(function (reason) {
        // reason contains your error.
    })
    .finally(function(){
        $ionicLoading.hide();
    }); 

另一种选择是使用拦截器:

app.config(function($httpProvider) {
  $httpProvider.interceptors.push(function($rootScope) {
    return {
      request: function(config) {
        $rootScope.$broadcast('loading:show')
        return config
      },
      response: function(response) {
        $rootScope.$broadcast('loading:hide')
        return response
      }
    }
  })
})

这将触发事件,事件本身将在 $rootScope:

中被拦截
app.run(function($rootScope, $ionicLoading) {
  $rootScope.$on('loading:show', function() {
    $ionicLoading.show({template: 'foo'})
  })

  $rootScope.$on('loading:hide', function() {
    $ionicLoading.hide()
  })
})

通过这种方式,每次执行 运行 长 http 请求时,您都设法 show/hide 加载指示器。

解释here.