草庐IT

javascript - Angular/Ionic 和异步 SQLite - 确保数据工厂在返回前初始化

coder 2023-07-20 原文

我正在使用 Ionic 编写 PhoneGap/Cordova 应用程序,并使用 SQLite(使用 ngCordova)进行持久存储。该应用程序的核心是从 SQLite 数据库中检索的项目的滚动列表。

listController.js

.controller('ListCtrl', [
  '$scope',
  'dataFactory',
  function($scope, dataFactory) {

    var items = dataFactory.getAllItems().then(function(data){
      $scope.allItems = data;
    });

  }
]);

dataFactory.js

.factory('dataFactory', [function($window, $log, $q, $cordovaSQLite, dummyDataGenerator){    

  var db_;

  // ...lots of SQLite fun in here
  // cascading async callbacks to load the database and inject dummy data
  var openDB_ = function(){...};
  var createTable_ = function(){...};
  // etc

  var getAllItems = function(){

    var q = $q.defer();
    $cordovaSQLite.execute(db_, sqlSelectString, []).then(
      function(results) {
        $log.log("SQL SELECT successful");
        var i, len, allItems = [];
        for(i = 0, len = results.rows.length; i < len; i++) {
          allItems.push(results.rows.item(i));
        }
        q.resolve(allItems);
      },
      function (err) {
        q.reject(err);
      }
    );
    return q.promise;
  };

  return { getAllItems: getAllItems };
]}); // <-- factory

最初我是直接返回工厂。 Controller 执行 getAllItems(),它在数据准备好之前运行。 View 最初是空的,仅在第二个 getAllItems()

后返回路线时显示任何内容

所以我尝试通过添加 factoryReady() 函数来延迟工厂的返回,并且只在所有内部数据库都准备好后才调用它

var factoryReady = function(){
  return {
    getAllItems: getAllItems
  };
};

现在有一个未定义的错误,因为 整个 工厂在第一次调用时不可用,而不是 getAllItems() 只是空手返回。我可以看到 SQL 数据库在适当的时候被正确写入,但是 Angular 在这完成之前抛出了一个异常。

我现在意识到这是可以预见的,我已经阅读了帖子 AngularJS : Initialize service with asynchronous data但不太明白如何实现排名靠前的答案(作者 joakimbl)

公开服务并确保在内部异步操作完成之前它不会被 Controller 调用的最佳方式是什么?我是否需要将整个服务作为 promise 返回,而不仅仅是 getAllItems 的结果?我试了一下,但现在很困惑。谢谢。

编辑

我还研究过在加载 View 时使用 ui-router 的 resolve http://blog.brunoscopelliti.com/show-route-only-after-all-promises-are-resolved但这并不能解决 SQL 数据/工厂的内部就绪问题。如果我返回 getAllCases 方法,那么它仍然会立即被调用,SQL 数据库中还没有任何内容,SQL 查询返回一个空结果集,promise 解析并呈现 View 。

最佳答案

设法让它在最后工作。将此张贴在这里以供遇到问题的其他人使用。

dataFactory.js

  • dataFactory.js 中使用异步 SQL 调用重写了所有私有(private)方法以返回 promise
  • 创建了一个公共(public) initDB 方法,该方法将调用链接到私有(private)方法(例如 openDB >> dropTable_ >> createTable_ 等)。还返回了一个 promise (空)
  • 立即从工厂返回initDBgetAllItems()

    .factory('dataFactory', [function($window, $log, $q, $cordovaSQLite, dummyDataGenerator){    
    
      var db_;
    
      // private methods - all return promises
    
      var openDB_ = function(dbName){
    
        var q = $q.defer();
        // ...call async SQL methods
        return q.promise;
      };
    
      var createTable_ = function(){
        var q = $q.defer();
        // ...call async SQL methods
        return q.promise;               
      };
    
      // ...etc
    
      // public methods
    
      var initDB = function(){
    
        var q = $q.defer();
        // successively call private methods, chaining to next with .then()
        openDB_("myDB").then(function(db){
          var schema = "...SQL schema here..."
          dropTable_(db, "FirstTable", schema).then(function(tableName){
            // ...etc
            // when all done, resolve the promise
            q.resolve();
          })
        })
        return q.promise;
      }
    
      var getAllItems = function(){
    
        var q = $q.defer();
        // ...call async SQL methods
        return q.promise;
      };
    
      return {
        initDB: initDB,
        getAllItems: getAllItems 
      };
    
    ]}); // <-- factory
    

app.js

  • 使用ui-routerresolve能力
  • 我之前的尝试没有正确注入(inject) promise
  • 向顶层抽象状态添加了一个resolve 以触发对initDB的调用
  • initDB 的 promise 注入(inject)子状态的 resolve 对象
  • 将解析对象注入(inject) Controller

    //应用程序路由(使用 ui-router) .config(函数($stateProvider, $urlRouterProvider){

    $stateProvider
    
      // top-level abstract state that houses Ionic side menu & nav
      .state('app', {
        url: '/app',
        abstract: true,
        templateUrl: "templates/sideMenu.html",
        resolve: {
          dbReady: function($log, dataFactory){
            // (1) init the DB
            return dataFactory.initDB().then(function(){
              $log.log("initDB promise resolved");
          });
        }
      }
    })
    
    // the following states are all child states of app
    
    .state('app.items', {
      url: "/items",
      views: {
        menuContent: {
          templateUrl: "templates/gbCaseList.html",
          // (3) now we can inject the items promise into our controller
          controller: function($scope, $log, items){
            // (4) uses resolved items variable injected by ui-router
            $scope.allItems = items;
          }
        }
      },
      resolve: {
        // (2) note that we MUST inject the dbReady promise, if we don't this will instantiate immediately
        items: function(dbReady, $log, dataFactory){
          // the following call returns a promise
          return dataFactory.getItems();
        }
      }
    })
    

现在一切正常。非常感谢这篇文章清理了我对 ui-router 的使用 Run controllers only after initialization is complete in AngularJS

关于javascript - Angular/Ionic 和异步 SQLite - 确保数据工厂在返回前初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27863874/

有关javascript - Angular/Ionic 和异步 SQLite - 确保数据工厂在返回前初始化的更多相关文章

  1. ruby-on-rails - Railstutorial : db:populate vs. 工厂女孩 - 2

    在railstutorial中,作者为什么选择使用这个(代码list10.25):http://ruby.railstutorial.org/chapters/updating-showing-and-deleting-usersnamespace:dbdodesc"Filldatabasewithsampledata"task:populate=>:environmentdoRake::Task['db:reset'].invokeUser.create!(:name=>"ExampleUser",:email=>"example@railstutorial.org",:passwo

  2. ruby-on-rails - 未初始化的常量 Psych::Syck (NameError) - 2

    在我的gem中,我需要yaml并且在我的本地计算机上运行良好。但是在将我的gem推送到ruby​​gems.org之后,当我尝试使用我的gem时,我收到一条错误消息=>"uninitializedconstantPsych::Syck(NameError)"谁能帮我解决这个问题?附言RubyVersion=>ruby1.9.2,GemVersion=>1.6.2,Bundlerversion=>1.0.15 最佳答案 经过几个小时的研究,我发现=>“YAML使用未维护的Syck库,而Psych使用现代的LibYAML”因此,为了解决

  3. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  4. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

    我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

  5. ruby-on-rails - ActionController::RoutingError: 未初始化常量 Api::V1::ApiController - 2

    我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc

  6. ruby - 这两个 Ruby 类初始化定义有什么区别? - 2

    我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是

  7. ruby - 为什么当我调用类的实例方法时,初始化不显示为方法? - 2

    我正在写一篇关于在Ruby中几乎一切都是对象的博客文章,我试图通过以下示例来展示这一点:classCoolBeansattr_accessor:beansdefinitialize@bean=[]enddefcount_beans@beans.countendend所以从类中我们可以看出它有4个方法(当然,除非我错了):它可以在创建新实例时初始化一个默认的空bean数组它可以计算它有多少个bean它可以读取它有多少个bean(通过attr_accessor)它可以向空数组写入(或添加)更多bean(也通过attr_accessor)但是,当我询问类本身它有哪些实例方法时,我没有看到默认

  8. ruby-on-rails - 在 Ruby on Rails 中发送响应之前如何等待多个异步操作完成? - 2

    在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.

  9. ruby-on-rails - 为什么在 Rails 5.1.1 中删除了 session 存储初始化程序 - 2

    我去了这个website查看Rails5.0.0和Rails5.1.1之间的区别为什么5.1.1不再包含:config/initializers/session_store.rb?谢谢 最佳答案 这是删除它的提交:Setupdefaultsessionstoreinternally,nolongerthroughanapplicationinitializer总而言之,新应用没有该初始化器,session存储默认设置为cookie存储。即与在该初始值设定项的生成版本中指定的值相同。 关于

  10. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

随机推荐