2017-02-10 116 views
1

我正在尝试使用SQLite plugin来构建Cordova/angular应用程序,以使其脱机工作,但我在查询数据库的承诺和异步方面遇到了很多麻烦,这是我的情况:角度嵌套循环承诺

我有5台配置是这样的:

表页与ID,标题,template_id和身体 表菜单通过ID和标签 表PageMenus通过ID和PAGE_ID和menu_id页和菜单 表关联带有id menu_id的body菜单和教导菜单中的“actual”元素的主体 ID为a的餐桌模板nd标签选择正确的视图

兼容性原因(我使用相同的代码为webapp和移动应用程序和webapp我在移动设备上调用我的API我下载设备上的所有内容)我需要以检索页面的格式如下:

{ 
    "id": 1 
    "body": "Welcome to the homepage", 
    "title": "Homepage", 
    "template_tag": "tab", 
    "menus": [ 
    { 
     "id": 3, 
     "tag": "home_menu", 
     "menu_items": [ 
     { 
      "menu_id": 3, 
      "body": "Movie" 
     }, 
     { 
      "menu_id": 3, 
      "body": "Restaurant" 
     }, 
     { 
      "menu_id": 3, 
      "body": "Messages" 
     }, 
     { 
      "menu_id": 3, 
      "body": "Systems" 
     } 
     ] 
    }, 
    { 
     "id": 62, 
     "tag": "user_menu", 
     "menu_items": [ 
     { 
      "menu_id": 62, 
      "body": "About" 
     }, 
     { 
      "menu_id": 62, 
      "body": "Updates" 
     }, 
     { 
      "menu_id": 62, 
      "body": "Help" 
     }, 
     { 
      "menu_id": 62, 
      "body": "Reset Password" 
     }, 
     { 
      "menu_id": 62, 
      "body": "Report/ Feedback" 
     } 
     ] 
    } 
    ] 
} 

我已经能够得到正确的格式,但我的问题是,控制器试图访问菜单的身体之前得到解决,所以我得到错误未定义,则此是我在工厂使用的代码:

return { 
    getHomePage: function() { 
    // other function 
    }, 
    getPage: function(id) { 
    var results = $q.defer(); 

    function request() { 
     var res = {}; 
     var queryPage = "SELECT pages.id, pages.body, pages.title, templates.tag AS template_tag FROM pages JOIN templates ON pages.template_id = templates.id WHERE pages.id = ?"; 
     $cordovaSQLite.execute(db, queryPage, [id]).then(function(page) { 
     res = page.rows.item(0); 
     res.menus = []; 
     var queryMenus = "SELECT menus.id, menus.tag FROM menus JOIN page_menus ON menus.id = page_menus.menu_id WHERE page_menus.page_id = ?"; 
     $cordovaSQLite.execute(db, queryMenus, [res.id]).then(function(menus) { 
      for (var i = 0; i < menus.rows.length; i++) { 
      var menu = { 
       id: menus.rows.item(i).id, 
       tag: menus.rows.item(i).tag, 
       menu_items: [] 
      }; 
      var queryMenuItems = "SELECT * FROM menu_items JOIN menus ON menu_items.menu_id = menus.id where menus.id = ?" 
      $cordovaSQLite.execute(db, queryMenuItems, [menus.rows.item(i).id]).then(function(menu_items) { 
       for (var i = 0; i < menu_items.rows.length; i++) { 
       menu.menu_items.push(menu_items.rows.item(i)); 
       } 
      }); 
      res.menus.push(menu); 
      }; 
      results.resolve(res); 
     }); 
     }); 
    }; 
    request(); 

    return results.promise; 
    }, 
    getMedia: function(id) { 
    // other function 
    } 
}; 
+0

如果您使用'ui-router',请查看'resolve'。问题在于,当数据不可用时请求数据,'resolve'方法允许您在加载状态之前加载数据,以确保满足您的期望。仅通过查看代码很难定义您的上下文。 –

回答

0

这是我最终会做(我发布它,即使我不认为会有人真正有用的,因为别人很大程度上是基于我的数据库结构):

var promisePage = $cordovaSQLite.execute(db, "SELECT p.*, t.tag AS template_tag FROM pages AS p JOIN templates AS t ON p.template_id = t.id WHERE p.id = ?", [id]); 
var promiseMenus = $cordovaSQLite.execute(db, "SELECT m.* FROM menus AS m JOIN page_menus AS pm ON m.id = pm.menu_id WHERE pm.page_id = ?", [id]); 
var promiseMenuItems = $cordovaSQLite.execute(db, "SELECT mi.* FROM menu_items AS mi JOIN menus AS m ON mi.menu_id = m.id JOIN page_menus AS pm ON pm.menu_id = m.id WHERE pm.page_id = ?", [id]); 

return $q.all([promisePage, promiseMenus, promiseMenuItems]).then(function(data) { 
    var page = data[0].rows.item(0); 
    var menus = data[1]; 
    var menuItems = data[2]; 
    // here there is some boring code to construct the page 
    return page; 

简单地说,不是在获取页面后查询菜单和菜单项的db,而是并行查询所有三个元素,然后在$ q.all中完成所有工作。

0

这是一个很好的做法,链承诺的方式:

getSomething: function(...) { 
    return requestReturningPromise1.then(function(resultOfPromise1) { 
     // Do something here (prepare next request,...) 
     return requestReturningPromise2; 
    }).then(function(resultOfPromise2) { 
     // Do something here (prepare next request,...) 
     return requestReturningPromise3;  
    }).then(function(resultOfPromise3) { 
     // Do something here (prepare next request,...) 
     return finalReturn;  
    }); 
} 

嵌套减少,这是更具可读性和易于调试。 所以把它应用到你的代码提供了这样的事情:

getPage: function(id) { 
    var res = {}; 
    var queryPage = "SELECT pages.id, pages.body, pages.title, templates.tag AS template_tag FROM pages JOIN templates ON pages.template_id = templates.id WHERE pages.id = ?"; 
    return $cordovaSQLite.execute(db, queryPage, [id]).then(function(page) { 
     res = page.rows.item(0); 
     res.menus = []; 
     var queryMenus = "SELECT menus.id, menus.tag FROM menus JOIN page_menus ON menus.id = page_menus.menu_id WHERE page_menus.page_id = ?"; 
     return $cordovaSQLite.execute(db, queryMenus, [res.id]); 
    }).then(function(menus) { 
     var menuPromises = []; 
     for (var i = 0; i < menus.rows.length; i++) { 
      var menu = { 
       id: menus.rows.item(i).id, 
       tag: menus.rows.item(i).tag, 
       menu_items: [] 
      }; 
      var queryMenuItems = "SELECT * FROM menu_items JOIN menus ON menu_items.menu_id = menus.id where menus.id = ?"; 
      var menuPromise = $cordovaSQLite.execute(db, queryMenuItems, [menus.rows.item(i).id]).then(function(menu_items) { 
       for (var i = 0; i < menu_items.rows.length; i++) { 
        menu.menu_items.push(menu_items.rows.item(i)); 
       } 
       return menu; 
      });  
      menuPromises.push(menuPromise);       
     } 
     return Promise.all(menuPromises);   
    }).then(function(menus) { 
     for (var i = 0; i < menus.length; i++) { 
      res.menus.push(menus[i]); 
     } 
     return res; 
    }); 
} 

注意,在上面的代码,所以你要使用它像这样在你的控制器服务本身会返回一个承诺:

MyService.getPage(id).then(function(page) { 
    // here, bind the result page to your controller scope ... 
});