微信小程序本地存储存储

by Nikita Kozlov

由Nikita Kozlov

如何利用本地存储构建快速的应用程序 (How to leverage Local Storage to build lightning-fast apps)

Users love fast, responsive apps. They don’t want to hear about how API calls take time. They just want to see updates immediately. Right now. And we as a developers should strive to provide that. So how can we?

用户喜欢快速响应的应用程序。 他们不想听到有关API调用如何花费时间的信息。 他们只想立即查看更新。 现在。 作为开发人员,我们应该努力做到这一点。 那我们怎么能呢?

The solution: storing those changes locally, then synchronizing them with your servers from time to time. But this gets way more complex when things like connection latency is taken into account.

解决方案:将这些更改存储在本地,然后不时将其与服务器同步。 但是,如果考虑到诸如连接延迟之类的问题,这将变得更加复杂。

Let’s take Medium for example. Medium users can recommend an article to their followers by tapping a little green heart (there’s one on this page, too ?). By tapping the heart a second time, the user can stop recommending it.

让我们以中为例。 中级用户可以通过点按一点绿色的心来向他们的关注者推荐一篇文章(此页面上也有一个?)。 通过第二次敲击心脏,用户可以停止推荐心脏。

功能很简单,但是边缘情况会导致很多问题 (The functionality is simple, but the edge cases cause lots of problems)

I don’t know exactly what happens inside Medium’s app, but for simplicity, lets imagine that the first tap adds an item to the recommendation list, and the second one removes it.

我不确切知道Medium的应用程序内部会发生什么,但是为简单起见,让我们想象一下,第一次点击会在推荐列表中添加一个项目,而第二次点击则会将其删除。

Let’s see what kinds of problems this could cause for us if we decided to add similar functionality to our app:

让我们看看如果我们决定向我们的应用程序添加类似的功能,这可能对我们造成什么问题:

  1. We should take into account that user can start tapping like crazy. This behavior could lead to a stream of events.我们应该考虑到用户可以开始疯狂地点击。 此行为可能导致事件流。
  2. Internet isn’t always fast. On a bad network connection, even simplest API calls could take several seconds to finish. During this time, the user could leave the current screen, then return.互联网并不总是很快。 在不良的网络连接上,即使最简单的API调用也可能需要几秒钟才能完成。 在这段时间内,用户可以离开当前屏幕,然后返回。
  3. From time to time, API calls can fail, and our system needs to be able to recover from such situations.API调用有时会失败,我们的系统需要能够从这种情况中恢复。
  4. Users can have multiple devices with the same app, or they can use both the mobile app version and the corresponding website in tandem. In either case, we should have a policy for synchronizing data with our back end to update its state.用户可以拥有具有同一应用程序的多个设备,或者可以同时使用移动应用程序版本和相应的网站。 无论哪种情况,我们都应该有一个与后端同步数据以更新其状态的策略。

This isn’t a full list of the challenges we face, but these are the ones this article will focus on addressing.

这不是我们面临的挑战的完整列表,但是本文将重点解决这些挑战。

定义问题 (Defining the problem)

Before we start discussing implementation, lets define our acceptance criteria. The task is to develop a feature that allows the user to add and remove items from a certain list. The list is stored on our back end.

在我们开始讨论实现之前,让我们定义我们的接受标准。 任务是开发一种功能,允许用户从特定列表中添加和删除项目。 该列表存储在我们的后端。

Implementation must fulfill the following requirements:

实现必须满足以下要求:

  1. The user interface reacts immediately to the user’s actions. The user wants to see the results of their actions immediately. If later we can’t synchronize those changes, we should notify our user, and roll back to the previous state.

    用户界面会立即对用户的动作做出React。 用户希望立即查看其操作的结果。 如果以后我们无法同步这些更改,则应通知我们的用户,并回滚到以前的状态。

  2. Interaction from multiple devices is supported. This doesn’t mean that we need to support changes in real time, but we do need to fetch the whole collection from time to time. Plus, our back end provides us with API endpoints for additions and removals, which we must use to support better synchronization.

    支持来自多个设备的交互。 这并不意味着我们需要实时支持更改,而是需要不时获取整个集合。 另外,我们的后端为我们提供了用于添加和删除的API端点,我们必须使用它们来支持更好的同步。

  3. Integrity of the data is guaranteed. Whenever a synchronization call fails, our app should recover gracefully from errors.

    保证数据的完整性。 每当同步调用失败时,我们的应用应从错误中正常恢复。

Luckily, we don’t need to implement the whole feature, but rather develop a storage mechanism that will allow us to implement it. Let’s investigate different ways to meet these requirements.

幸运的是,我们不需要实现整个功能,而需要开发一种存储机制来实现它。 让我们研究满足这些要求的不同方法。

直截了当的方法 (The straight-forward approach)

The first solution that comes to mind is to store a local copy of the list, then update it when the user makes a change.

我想到的第一个解决方案是存储列表的本地副本,然后在用户进行更改时对其进行更新。

Most of the problems with this approach are related to race conditions or API call failures, for example:

这种方法的大多数问题都与竞争条件或API调用失败有关,例如:

  1. Collisions between fetching and changing the list. Lets imagine that we started fetching items from our back end to update our local storage, and the user made a change before that operation finished. This would lead to a merge conflict between fetched list and the local one. So we need to distinguish, for example, between an item that wasn’t added yet and an item that was already removed from the web or another device.

    获取和更改列表之间的冲突。 假设我们开始从后端获取项目以更新本地存储,并且用户在该操作完成之前进行了更改。 这将导致在获取的列表和本地列表之间发生合并冲突。 因此,例如,我们需要区分尚未添加的项目和已经从网络或其他设备上移除的项目。

  2. API call failure. Users can make lots of changes quickly, and they can also revert them quickly. For example, users can add an item to a list, then remove them, then add them back. If the first addition fails, then we should recover from it. In this case, we need to remove the item from the list. But that would ruin the integrity of our data, because the item should actually be on the list, since the last call we made was an addition and it wasn’t finished yet.

    API调用失败。 用户可以快速进行许多更改,也可以快速还原它们。 例如,用户可以将项目添加到列表中,然后将其删除,然后再添加回列表中。 如果第一次添加失败,那么我们应该从中恢复。 在这种情况下,我们需要从列表中删除该项目。 但这会破坏我们数据的完整性,因为该项目实际上应该在列表中,因为我们上次调用是添加操作,并且尚未完成。

Even though there could be a way to make this approach work, I would argue that local storage should keep more information than just the final expected result. This will allow us to recover from all problems we may encounter.

即使有办法使这种方法行得通,我还是认为本地存储应该保留更多信息,而不仅仅是最终的预期结果。 这将使我们从可能遇到的所有问题中恢复过来。

让我们保留用户所做的所有操作的历史记录 (Let’s keep history of everything the user does)

Here’s a different approach: let’s keep the list we fetched from the API, as well as record everything the user has done. Every record would match an API call (“add” and “remove” respectively).

这是另一种方法:让我们保留从API中获取的列表,并记录用户所做的一切。 每个记录都将匹配一个API调用(分别为“添加”和“删除”)。

Once our API call finishes, we can update our local copy and remove the record from our history. When we want to synchronize the user’s browser with our back end, we just fetch the version of that list and replace our copy.

API调用完成后,我们可以更新本地副本并将记录从历史记录中删除。 当我们想将用户的浏览器与后端同步时,我们只获取该列表的版本并替换我们的副本。

We no longer have any problems with API call failure, because we know the exact state before the call, and can just drop that record from the history without losing data integrity.

API调用失败不再有任何问题,因为我们知道调用之前的确切状态,并且可以从历史记录中删除该记录而不会丢失数据完整性。

The main problem with this is performance. Every time we want to check whether a particular item is in the list, we need to go through all the records to calculate what our user should expect to see.

与此相关的主要问题是性能。 每次我们要检查列表中是否有特定项目时,我们都需要遍历所有记录以计算用户应该看到的内容。

Of course, performance depends on the amount of interactions our user can do within a certain timeframe, and the way the data is stored. Plus keep in mind that premature optimization is the root of all evil, so if you don’t have this problem, then probably this is a way to go.

当然,性能取决于我们的用户在特定时间范围内可以进行的互动数量以及数据的存储方式。 此外,请记住, 过早的优化是万恶之源 ,因此,如果您没有这个问题,那么也许这是一条路。

I think that this approach is great when user creates the content in the app, because it exposes lots of ways for handling synchronization issues. But our problem is simpler than that, so we should be able to make some optimizations and further increase performance.

我认为这种方法在用户在应用程序中创建内容时非常有用,因为它公开了许多处理同步问题的方法。 但是我们的问题要简单得多,因此我们应该能够进行一些优化并进一步提高性能。

中间立场 (The middle ground)

It’s possible to have just enough information to recover from negative cases. Having two extra lists — one for ongoing additions, and one for ongoing removals — should be enough. To ensure data integrity, you would just need to apply a few rules:

可能只有足够的信息可以从负面案例中恢复过来。 拥有两个额外的列表-一个用于正在进行的添加,另一个用于正在进行的删除-应该就足够了。 为了确保数据完整性,您只需要应用一些规则:

  1. Lists with additions and removals have priority over the main list. For example, let’s say an item is in both the removals list and in the main list. When the browser checks to see whether the item is in the list, it should return false.

    具有添加项和删除项的列表优先于主列表。 例如,假设一个项目在清除列表和主列表中。 当浏览器检查该项目是否在列表中时,它应该返回false。

  2. One item can’t be in both lists at once. If the user made multiple actions on a single item, the latest change should have priority. For example, if the user added and then removed the item, as a result it should be in the list for removals. It doesn’t matter whether the item is in the main list or not.

    一项不能同时出现在两个列表中。 如果用户对单个项目执行了多项操作,则最新更改应具有优先权。 例如,如果用户添加然后删除了该项目,则结果应在删除列表中。 该项是否在主列表中都没有关系。

  3. Only after the last API call for a certain item has finished can it be removed from the corresponding list. For example, the user could have added the item, removed it, then added it again before the first call is finished. In this case, the item would be in the list for additions. But it should be removed from there only after the second addition is finished. This can be achieved by assigning an ID to each entry in those lists. Later, after API call is finished, the entry would be removed using this ID.

    只有在完成对特定项目的最后一次API调用之后,才能将其从相应列表中删除。 例如,用户可能已经添加,删除了该项目,然后在第一个调用结束之前再次添加了该项目。 在这种情况下,该项目将在添加列表中。 但是,只有在第二次添加完成后才能从那里将其删除。 这可以通过为这些列表中的每个条目分配一个ID来实现。 稍后,API调用完成后,将使用此ID删除条目。

  4. After every API call, the main list should be updated. The main list should reflect the actual state of the backend to the best of our knowledge. So in the case of consecutive addition and removal, even though from app side it would looks like item was not in the list, after the first call we should add it to the main list.

    在每个API调用之后,应更新主列表。 据我们所知,主要列表应反映后端的实际状态。 因此,在连续添加和删除的情况下,即使从应用程序的角度来看,项目看起来也不在列表中,但在第一次调用后,我们应该将其添加到主列表中。

关于API调用失败的几句话 (A few words about API call failures)

There are different reasons why an API call can fail. Some of them temporary, some of them not. Some of them are fatal, and some of them are possible to recover from. Regardless of the solution, even failed requests should return some information about the cause of the problem.

API调用失败的原因有多种。 其中一些是临时的,有些不是。 其中一些是致命的,其中一些是可以恢复的。 无论解决方案如何,即使失败的请求也应返回有关问题原因的一些信息。

I think that HTTP status codes are perfect for this. For example, if the status code is 504 Gateway Timeout, then retrying could be a good idea, but if it is 400 Bad Request, then most likely some client logic is wrong and simple retry logic won’t help. Some of them, like 401 Unauthorized, could require some user actions. 410 Gone or 404 Not Found during the removal call could mean that the user removed this item from a different device and most likely we can even tell user that the operation was successful, since user’s intention is fulfilled.

我认为HTTP状态代码非常适合此操作。 例如,如果状态码是504网关超时,那么重试可能是个好主意,但是如果它是400错误的请求,则很可能某些客户端逻辑是错误的,简单的重试逻辑将无济于事。 其中有些(例如401未经授权)可能需要某些用户操作。 在移除通话期间410 Gone404 Not Found可能表示用户已从其他设备移除了该项目,并且很可能我们甚至可以告诉用户操作成功,因为用户的意图已得到满足。

If for some reason your API doesn’t use proper HTTP status codes (I don’t even want to know why), it still should provide information regarding the cause of an issue. Otherwise, you could run into a weird issues. For example, if the call for removal failed because item is not in the list anymore, but we won’t have information about the cause, then the application would think that item is in the list until the next round of fetching the whole list.

如果由于某种原因您的API没有使用正确的HTTP状态代码(我什至不想知道为什么),它仍应提供有关问题原因的信息。 否则,您可能会遇到奇怪的问题。 例如,如果呼叫去除失败,因为产品不在列表中了,但我们不会有关于原因的信息,那么该应用程序会认为该项目在列表中,直到下一轮获取整个列表。

结论 (Conclusion)

The first solution was a simple list. It was fast, but handling negative cases was difficult.

第一个解决方案是一个简单的列表。 速度很快,但是处理负面案件很困难。

In the second approach, we created a data structure that acts like a list, but persisted the records of all the changes made. This could handle negative cases, but it was much slower.

在第二种方法中,我们创建了一个数据结构,其作用类似于列表,但保留了所有更改的记录。 这可以处理负面案件,但速度要慢得多。

Our middle ground was a solution that — from outside — still acts like a list. But it allows us to balance performance and easily recovery from errors.

我们的中间立场是一种解决方案,从外部来看,仍然像清单一样。 但这使我们能够平衡性能并轻松地从错误中恢复。

The issues mentioned in this article are only one side of the problem. The other is the amount of API calls made. If the user performs a lot of similar interactions, we can try to minimize the amount of API calls made. This optimization affects the structure of our local storage as well.

本文提到的问题只是问题的一方面。 另一个是进行的API调用次数。 如果用户执行许多类似的交互操作,我们可以尝试减少API调用的数量。 这种优化也会影响我们本地存储的结构。

I will discuss this and propose additional solution to these issues in my next articles.

我将在以后的文章中对此进行讨论并提出针对这些问题的其他解决方案。

Thank you for you time reading this article. If you like it, don’t forget to click the ? below. You can also follow me on Twitter.

感谢您抽出宝贵的时间阅读本文。 如果喜欢,不要忘记单击“?”。 下面。 您也可以在Twitter上关注我。

翻译自: https://www.freecodecamp.org/news/how-leverage-local-storage-to-build-lightning-fast-apps-4e8218134e0c/

微信小程序本地存储存储

微信小程序本地存储存储_如何利用本地存储构建快速的应用程序相关推荐

  1. 微信小程相对图片路径_微信小程序----相对路径图片不显示

    出现场景 在本地调试的时候本地图片显示,但是手机浏览的时候本地图片不显示. 出现图片不显示的原因 小程序只支持网络路径和base64的图片.图片转base64在线工具 处理方法 将图片都放到服务器,然 ...

  2. 微信小程序控制盒子显示隐藏_微信小程序动态的显示或隐藏控件的方法(两种方法)...

    在微信小程序开发时,经常要用到一个控件会根据不同的情况和环境动态显示与隐藏这种情况,下面就来实践一把!上效果先 它的实现方法有两种, 第一种方法:单选法,就是隐藏与显示根据条件二选一,代码如下: 我是 ...

  3. 微信小程序控制盒子显示隐藏_微信小程序点击控制元素的显示与隐藏

    微信小程序点击控制元素的显示与隐藏 首先我们先来看一下单个点击效果 我们来看一下wxml中的代码: 更多内容 更多> 2017-07-27 下面的是js中的主要代码: data: { shows ...

  4. java程序ssh置顶_使用shell脚本启动远程(SSH)Java应用程序不会返回本地提示

    我见过类似的问题,所有已解决的问题已经解决/不适用. 我在启动Java应用程序的远程计算机中有一个bash脚本.相关的行将是: #!/usr/bin/env bash ... java -cp /fu ...

  5. 行存储索引改换成列存储索引_如何使用列存储索引来改善数据仓库登台环境

    行存储索引改换成列存储索引 My team and I were recently tasked with refactoring older data marts, particularly tho ...

  6. 微信小店二次开发_微信小店二次开发功能套餐列表

    本商品包括微信小店二次功能开发套餐. [商品介绍]以下费用均为一次性费用.永久使用. 套餐一: 800元 订单查询:用户查询自己最近30天之内的订单记录. 实时通知:用户付款成功后,实时通知用户订单详 ...

  7. 千里眼摄像头支持对象存储吗_视频监控对象存储

    一. 中东市场,国际安防厂家活跃 Milestone.Genetec.Thales.Honeywell.Bosch.Hikivision.Dahua , Tyco, Samsung, AXIS,Pec ...

  8. python怎么存储数据_【Python】存储数据

    很多程序都要求用户输入某种信息,如让用户存储游戏首选项或者提供可视化数据,不管专注什么,程序都要将数据进行存储,那么如何存储呢? JSON(JavaScript Object Notation)格式最 ...

  9. ceph存储原理_赠书 | Linux 开源存储全栈详解——从Ceph到容器存储

    // 留言点赞赠书我有书,你有故事么?留言说出你的存储故事留言点赞前两名,免费送此书截止日期12.27号12.30号公布名单 // 内容简介 本书致力于帮助读者形成有关Linux开源存储世界的细致的拓 ...

最新文章

  1. Android系统移植与调试之-------如何修改Android设备添加重启、飞行模式、静音模式等功能(一)...
  2. 使用随机森林(Random Forest)进行特征筛选并可视化
  3. 静态链表的插入和删除
  4. java同步方法完成案例_Java同步代码块和同步方法原理与应用案例详解
  5. 交易平台基本密钥处理流程(SJL05加密机)
  6. php下字符与二进制互转函数,PHP 字符串与二进制互转
  7. python可以直接打印中午吗_Python print不能立即打印的解决方式
  8. 博士申请 | 香港中文大学(深圳)陈冠英课题组招收CV/ML方向全奖博士生
  9. LightOJ - 1027 A Dangerous Maze —— 期望
  10. Croppic – 免费开源的 jQuery 图片裁剪插件
  11. zblog音频MP3播放器插件
  12. opencv抠人像_卸载PS吧!这个小程序就能一键AI抠图,超简单!
  13. python键_Python键盘按键模拟
  14. py 操作Mysql数据库
  15. java零基础自学教程视频,详细说明
  16. mysql表analyze_MySQL ANALYZE Optimize Check Table使用详解
  17. win2008服务器共享文件夹权限设置,win2008文件夹共享权限怎么设置
  18. DBMS_AUDIT_MGMT.FLUSH_UNIFIED_AUDIT_TRAIL过程
  19. C++ 函数模板 实例化和具体化
  20. Xshell快速命令集解放生产力

热门文章

  1. sqlserver的登陆操作
  2. jquery-自定义通用方法-jquery通用方法-所有对象的通用方法
  3. django-编辑学生
  4. zabbix监控MHA及自动启动
  5. CAICT:2015年全球云计算市场规模522亿美元
  6. Android Studio 代码混淆
  7. C#中HTML和UBB互相转换的代码
  8. linux服务器禁止ping和允许ping的方法
  9. morphological antialiasing
  10. Mac系统下SVN命令