javascript 使用参数缓存 URL 视图/状态
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26591335/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Caching URL view/state with parameters
提问by Namek
I'm making a mobile app using Cordova and AngularJS. Currently I have installed ui-router for routing but I'm open to any other alternative for routing.
我正在使用 Cordova 和 AngularJS 制作一个移动应用程序。目前我已经安装了用于路由的 ui-router,但我愿意接受任何其他路由选择。
My desire: I want to cache certain views bound with parameters. In other words I want to cache paths (or pages).
我的愿望:我想缓存某些绑定参数的视图。换句话说,我想缓存路径(或页面)。
Example situation: let's say that we see some dashboard page, click on some book cover which redirects to the path book/2
. This path is being loaded for the first time into app. Router redirects from HomeController
to BooksController
(whatever the name). Now the BooksController
loads data for given $stateParams
(book id = 2) and creates view filled with info about chosen book.
示例情况:假设我们看到一些仪表板页面,单击一些重定向到 path 的书籍封面book/2
。此路径是第一次加载到应用程序中。路由器重定向自HomeController
到BooksController
(无论名称如何)。现在BooksController
加载给定$stateParams
(书籍 id = 2)的数据并创建充满所选书籍信息的视图。
What I want in this situation:
在这种情况下我想要什么:
- I go back to the dashboard page - it is already loaded (cached?)
- I choose book #2 again
- Controller or router notices that data about this book is already loaded
- The view isn't being recreated, instead it's being fetched from cache
- 我回到仪表板页面 - 它已经加载(缓存?)
- 我再次选择第 2 本书
- 控制器或路由器通知有关这本书的数据已经加载
- 视图没有被重新创建,而是从缓存中获取
Actually, it would be best to cache everything what I visit based on path. Preloading would be cool too.
实际上,最好根据路径缓存我访问的所有内容。预加载也会很酷。
Reason: performance. When I open some list of books then I want it to show fast. When view is being created every time, then animation of page change looks awful (it's not smooth).
原因:性能。当我打开一些书单时,我希望它快速显示。每次创建视图时,页面更改的动画看起来很糟糕(不流畅)。
Any help would be appreciated.
任何帮助,将不胜感激。
EDIT:
编辑:
First of all, since I believe it's a common problem for many mobile HTML app programmers, I'd like to precise some information:
首先,由于我相信这是许多移动 HTML 应用程序程序员的常见问题,因此我想提供一些信息:
- I'm not looking for hacks but a clear solution ifpossible.
- Data in the views uses AngularJS, so YES, there arethings like
ng-bind
,ng-repeat
and so on. - Cachingis needed for bothdataand DOM elements. As far as I know, browser's layout operation is not as expensive as recreating whole DOM tree. And repaint is not what we can omit.
- Having separate controllers is a natural thing. Since I could leave without it I cannot imagine how it would work anyway.
- 如果可能的话,我不是在寻找黑客,而是寻找明确的解决方案。
- 视图中的数据使用 AngularJS,所以是的,有诸如, 之类的东西。
ng-bind
ng-repeat
- 数据和DOM 元素都需要缓存。据我所知,浏览器的布局操作并不像重新创建整个 DOM 树那么昂贵。而重绘不是我们可以省略的。
- 拥有单独的控制器是很自然的事情。因为我可以离开它,所以我无法想象它会如何运作。
I've got some semi-solutions but I'm gonna be strict about my desire.
我有一些半解决方案,但我会严格要求我的愿望。
Solution 1.
解决方案1。
Put all views into one file (I may do it using gulp builder) and use ng-show
. That's the simplest solution and I don't believe that anyone knowing AngularJS would not think about it.
将所有视图放入一个文件中(我可以使用 gulp builder 来完成)并使用ng-show
. 这是最简单的解决方案,我不相信任何了解 AngularJS 的人都不会考虑它。
A nice trick(from @DmitriZaitsev) is to create a helper function to show/hide element based on current location path.
一个不错的技巧(来自@DmitriZaitsev)是创建一个辅助函数来根据当前位置路径显示/隐藏元素。
Advantages:
好处:
- It's easy.
- KIND OF preload feature.
- 这简单。
- 一种预加载功能。
Disadvantages:
缺点:
- all views have to be in a single file. Don't ask why it's not convenient.
- Since it's all about mobile devices, sometimes I'd like to "clear" memory. The only way I can think of is to remove those children from DOM. Dirty but ok.
- I cannot easily cache /book/2 and /book/3 at the same time. I would have to dynamically create DOM children on top of some templates for each view bound with parameters.
- 所有视图都必须在一个文件中。不要问为什么不方便。
- 由于这都是关于移动设备的,有时我想“清除”内存。我能想到的唯一方法是从 DOM 中删除这些孩子。脏,但还好。
- 我无法轻松地同时缓存 /book/2 和 /book/3。我必须为每个绑定参数的视图在一些模板之上动态创建 DOM 子项。
Solution 2.
解决方案 2。
Use Sticky States AND Future States from ui-router-extraswhich is awesome.
使用ui-router-extras 中的粘性状态和未来状态,这很棒。
Advantages:
好处:
- Separated views.
- Very clear usage, very simple since it's just a plugin for
ui-router
. - Can create dynamic substates. So it would be possible to cache
book1
,book2
but I'm not sure aboutbook/1
andbook/2
- 分开的看法。
- 非常清晰的用法,非常简单,因为它只是
ui-router
. - 可以创建动态子状态。所以可以缓存
book1
,book2
但我不确定book/1
和book/2
Disadvantages:
缺点:
- Again, I'm not sure but I didn't found an example with caching a pair/tuple
(view, parameters)
. Other than that it looks cool.
- 同样,我不确定,但我没有找到缓存一对/tuple的示例
(view, parameters)
。除此之外,它看起来很酷。
采纳答案by Dmitri Zaitsev
This is precisely the problem I had to solve for my site 33hotels.com. You can check it and play with the tabs "Filter" and "Filter List" (corresponding to different Routes), and see that the View is updated instantly without any delay!
这正是我必须为我的网站33hotels.com解决的问题。您可以检查并使用“过滤器”和“过滤器列表”选项卡(对应不同的路由),并看到视图立即更新,没有任何延迟!
How did I do it? The idea is surprisingly simple - get rid of the Router!
我是怎么做的?这个想法非常简单 - 摆脱路由器!
Why? Because the way the Router works is it re-compilesthe View upon every single Route change. Yes, Angular does cache the Templatebut not the compiled View populated with data. Even if data do not change! As the result, when I used the Router in the past, the switch always felt sluggish and non-reactive. Every time I could notice annoying delay, it was a fraction of second but still noticeable.
为什么?因为路由器的工作方式是在每次 Route 更改时重新编译View 。是的,Angular 会缓存模板,但不会缓存填充数据的编译视图。即使数据不改变!结果,我以前用Router的时候,总是感觉switch不灵,反应迟钝。每次我都能注意到烦人的延迟,它只是几分之一秒,但仍然很明显。
Now the solution I used? Don't re-compile your Views! Keep them inside your DOM at all times! Then use ng-hide
/ng-show
to hide/show them depending on the routes:
现在我使用的解决方案?不要重新编译您的视图!始终将它们保存在您的 DOM 中!然后根据路线使用ng-hide
/ng-show
隐藏/显示它们:
<div ng-show="routeIs('/dashboard')">
<-- Your template for Dashboard -->
</div>
<div ng-show="routeIs('/book')">
<-- Your template for Book -->
</div>
Then create a function routeIs(string)
inside your Controller
to test if $location.path()
matches string
, or begins with string
as I am using it. That way I still get my View for all pathes like /book/2
. Here is the function I am using:
然后routeIs(string)
在您的内部创建一个函数Controller
来测试是否$location.path()
匹配string
,或者以string
我正在使用的方式开始。这样我仍然可以获取所有路径的视图,例如/book/2
. 这是我正在使用的功能:
$scope.routeBegins = function () {
return _.some(arguments, function (string) {
return 0 === $location.path().indexOf(string);
});
};
So no need to be smart with caching - just keep it in the DOM. It will cache your Views for you!
所以不需要对缓存很聪明 - 只需将它保存在 DOM 中。它将为您缓存您的视图!
And the best part is - whenever your data is changed, Angular will instantly update all the Views inside your DOM, even the hidden ones!
最好的部分是 - 每当您的数据发生更改时,Angular 都会立即更新 DOM 中的所有视图,甚至是隐藏的视图!
Why is this awesome? Because, as user, I don't have to wait for all the parsing and compiling at the moment I want to see the result. I want to click the tab and see my results immediately! Why should the site wait for me to click it and thenbegin all the re-compiling as I am waiting? Especially when this could be easily done before, during the time my computer is idle.
为什么这很棒?因为,作为用户,我不需要在我想看到结果的那一刻等待所有的解析和编译。我想单击选项卡并立即查看我的结果!为什么网站要等待我点击它,然后在我等待的时候开始所有的重新编译?尤其是当这在以前很容易做到的时候,在我的电脑空闲的时候。
Is there any downside? The only real one I can think of is loading memory with more DOM elements. However, this actual byte size of my views is negligible, comparing e.g. with all JS, CSS and images.
有什么缺点吗?我能想到的唯一真正的方法是用更多的 DOM 元素加载内存。但是,与所有 JS、CSS 和图像相比,我的视图的实际字节大小可以忽略不计。
Another possible but avoidable downside is the re-compilation cost of the hidden views. This is where you can get smart and avoid computation-heavy parts depending on the current routes. Also, you are not re-compiling the whole View, just the parts affected by data changes, which also lowers computational cost.
另一个可能但可以避免的缺点是隐藏视图的重新编译成本。在这里,您可以变得聪明并根据当前路线避免计算量大的部分。此外,您无需重新编译整个 View,只需重新编译受数据更改影响的部分,这也降低了计算成本。
I find it quite remarkable that everyone is using Routes and seems to be completely unaware (or ignorant) of this problem.
我发现每个人都在使用 Routes 并且似乎完全不知道(或无知)这个问题是非常了不起的。
回答by Astravagrant
If you're using ui.router, then you should take a look at ui.router extras, specifically the sticky states module. This allows you to cache the state 'tree' (including rendered views) so they don't have to be compiled or re-rendered on state changes.
如果您正在使用 ui.router,那么您应该查看 ui.router extras,特别是粘性状态模块。这允许您缓存状态“树”(包括渲染视图),因此不必在状态更改时编译或重新渲染它们。
http://christopherthielen.github.io/ui-router-extras/
http://christopherthielen.github.io/ui-router-extras/
Here's a demo:
这是一个演示:
http://christopherthielen.github.io/ui-router-extras/example/sticky/#/
http://christopherthielen.github.io/ui-router-extras/example/sticky/#/
回答by Naeem Shaikh
1) About static pages in the app (views), angular takes care of loading them.
1) 关于应用中的静态页面(视图),Angular 负责加载它们。
for example: for your dashboard page you need not worry about caching the page, as angular will take care of it. Angular will only load the dashboard view once and on all next requests for the dashboard view, angular will just show you the view(not load the file for view), if it is all a static view without any data loaded by ajax calls.
例如:对于您的仪表板页面,您无需担心缓存页面,因为 angular 会处理它。Angular 只会加载仪表板视图一次,并且在仪表板视图的所有下一个请求中,如果它都是静态视图,而没有 ajax 调用加载任何数据,则 Angular 只会向您显示视图(不加载文件以供查看)。
2) if your dashboard is itself loading the book list(or similar data) via ajax, then you can tell your controller to only load the data once and store it to localstorage and on subsequent requests to the dashboard page can only load the data from the localStorage.
2)如果您的仪表板本身通过ajax加载书籍列表(或类似数据),那么您可以告诉您的控制器只加载一次数据并将其存储到localstorage,并且在对仪表板页面的后续请求中只能从本地存储。
3) similar approach can be used when your BooksController
loads the data into a view. You can check in your BooksController if the request for a particular book is been previously made and if not your can store it to localstorage or database. and if the data was previously requested then you can load the same data from the storage without making a request to server.
3)BooksController
将数据加载到视图中时可以使用类似的方法。您可以在 BooksController 中检查是否先前已发出对特定书籍的请求,否则可以将其存储到 localstorage 或数据库中。如果之前请求过数据,那么您可以从存储中加载相同的数据,而无需向服务器发出请求。
Example situation:
示例情况:
say user makes request for book1, then
假设用户请求 book1,然后
- your controller i.e BooksController check whether the same data was requested before,
- if not, you can load the data via the ajax call from server and also save it to local storage.
- if it was loaded before you will load the data stored in the localstorage or in the database.
- 您的控制器即 BooksController 检查之前是否请求过相同的数据,
- 如果没有,您可以通过来自服务器的 ajax 调用加载数据并将其保存到本地存储。
- 如果它是在加载存储在本地存储或数据库中的数据之前加载的。