如何设计一个同时安全的多用户 Ajax Web 应用程序

发布于 2024-10-14 12:52:22 字数 556 浏览 10 评论 0 原文

我有一个网页,显示来自服务器的大量数据。通信是通过ajax完成的。

每次用户交互并更改此数据(假设用户 A 重命名某些内容)时,它都会告诉服务器执行该操作,然后服务器返回新更改的数据。

如果用户B同时访问该页面并创建一个新的数据对象,它将再次通过ajax告诉服务器,服务器将为用户返回新的对象。

在 A 的页面上,我们有带有重命名对象的数据。在 B 的页面上,我们有一个新对象的数据。在服务器上,数据既有重命名的对象又有新的对象。

当多个用户同时使用页面时,我可以选择哪些选项来保持页面与服务器同步?

诸如锁定整个页面或在每次更改时将整个状态转储给用户之类的选项是可以避免的。

如果有帮助,在此特定示例中,网页会调用在数据库上运行存储过程的静态 Web 方法。存储过程将返回它已更改的所有数据,仅此而已。然后,静态 Web 方法将存储过程的返回转发给客户端。

赏金编辑:

如何设计一个使用 Ajax 与服务器通信但又避免并发问题的多用户 Web 应用程序?

即并发访问数据库上的功能和数据,没有任何数据或状态损坏的风险

I have a web page that shows a large amount of data from the server. The communication is done via ajax.

Every time the user interacts and changes this data (Say user A renames something) it tells the server to do the action and the server returns the new changed data.

If user B accesses the page at the same time and creates a new data object it will again tell the server via ajax and the server will return with the new object for the user.

On A's page we have the data with a renamed object. And on B's page we have the data with a new object. On the server the data has both a renamed object and a new object.

What are my options for keeping the page in sync with the server when multiple users are using it concurrently?

Such options as locking the entire page or dumping the entire state to the user on every change are rather avoided.

If it helps, in this specific example the webpage calls a static webmethod that runs a stored procedure on the database. The stored procedure will return any data it has changed and no more. The static webmethod then forwards the return of the stored procedure to the client.

Bounty Edit:

How do you design a multi-user web application which uses Ajax to communicate with the server but avoids problems with concurrency?

I.e. concurrent access to functionality and to data on a database without any risk of data or state corruption

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

梦幻的心爱 2024-10-21 12:52:23

这些维基百科页面可能有助于增加了解并发并发计算用于设计ajax Web 应用程序 要么 拉动推送状态事件 (EDA) 消息传递模式中的 orient_middleware" rel="nofollow">消息。基本上,消息被复制到响应更改事件和同步请求的通道订阅者。

基于网络的并发协作软件有多种形式

有许多用于 etherpad-lite 的 HTTP API 客户端库,一个协作实时编辑器

django-realtime-playground 使用各种实时技术在 Django 中实现实时聊天应用程序,例如Socket.io

AppEngine 和 AppScale 均实现 AppEngine Channel API;它与 Google Realtime API 不同,googledrive/realtime-playground

These Wikipedia pages may help add perspective to learning about concurrency and concurrent computing for designing an ajax web application that either pulls or is pushed state event (EDA) messages in a messaging pattern. Basically, messages are replicated out to channel subscribers which respond to change events and synchronization requests.

There are many forms of concurrent web-based collaborative software.

There are a number of HTTP API client libraries for etherpad-lite, a collaborative real-time editor.

django-realtime-playground implements a realtime chat app in Django with various real-time technologies like Socket.io.

Both AppEngine and AppScale implement the AppEngine Channel API; which is distinct from the Google Realtime API, which is demonstrated by googledrive/realtime-playground.

筱武穆 2024-10-21 12:52:23

服务器端推送技术就是解决问题的方法。 Comet 是(或者曾经是?)一个流行词。

您采取的特定方向在很大程度上取决于您的服务器堆栈以及您/它的灵活性。如果可以的话,我会看看 socket.io,它提供了 websockets 的跨浏览器实现,它提供了一种与服务器进行双向通信的非常简化的方式,允许服务器将更新推送到客户端。

特别是,请参阅库作者的演示,它几乎完全演示了您所描述的情况。

Server-side push techniques are the way to go here. Comet is (or was?) a buzz word.

The particular direction you take depends heavily on your server stack, and how flexible you/it is. If you can, I would take a look at socket.io, which provides a cross-browser implementation of websockets, which provide a very streamline way to have bidirectional communication with the server, allowing the server to push updates to the clients.

In particular, see this demonstration by the library's author, which demonstrates almost exactly the situation you describe.

谈下烟灰 2024-10-21 12:52:22

概述:

  • 简介
  • 服务器架构
  • 客户端架构
  • 更新案例
  • 提交案例
  • 冲突案例
  • 性能与性能可扩展性

嗨 Raynos,

我不会在这里讨论任何特定的产品。其他人提到的是一个很好的工具集,值得一看(也许将 node.js 添加到该列表中)。

从体系结构的角度来看,您似乎遇到了与版本控制软件中相同的问题。一个用户签入对对象的更改,另一个用户想要以另一种方式更改同一对象=>冲突。您必须将用户更改集成到对象,同时能够及时有效地交付更新,检测并解决上述冲突。

如果我处在你的位置,我会开发这样的东西:

1. 服务器端:

  • 确定一个合理的级别,在该级别上定义我所说的“原子工件”(页面?页面上的对象?值物体内部?)。这将取决于您的网络服务器、数据库和服务器。缓存硬件、用户数、对象数等。这不是一个容易做出的决定。

  • 对于每个原子工件有:

    • 应用程序范围内的唯一 ID
    • 递增的版本 ID
    • 用于写访问的锁定机制(可能是互斥锁)
    • 环形缓冲区内的小历史记录或“变更日志”(共享内存非常适合这些)。单个键值对也可能没问题,尽管可扩展性较差。请参阅http://en.wikipedia.org/wiki/Circular_buffer
    • 那些

  • 服务器或伪-服务器组件能够有效地将相关变更日志传递给连接的用户。观察者模式是您的朋友。

2. 客户端:

  • 能够与上述服务器建立长期运行的 HTTP 连接的 JavaScript 客户端,或者使用轻量级轮询。

  • 一个 javascript 工件更新程序组件,当连接的 javascript 客户端通知监视工件历史记录中的更改时,该组件会刷新站点内容。 (同样,观察者模式可能是一个不错的选择)

  • 一个 javascript 工件提交器组件,可能会请求更改原子工件,尝试获取互斥锁。它将通过比较已知的客户端工件版本 ID 和当前的服务器端工件版本 ID 来检测工件的状态是否在几秒钟前被另一个用户更改(JavaScript 客户端的延迟和提交过程因素)。

  • 一个 JavaScript 冲突解决程序,允许人类做出哪个更改是正确的决定。您可能不想只告诉用户“有人比您更快。我删除了您的更改。去哭吧。”。来自技术差异或更用户友好的解决方案的许多选项似乎都是可能的。

那么它会如何滚动...

案例 1:用于更新的序列图:

  • 浏览器呈现页面
  • javascript“看到”工件,每个工件至少有一个值字段、唯一的和版本 ID
  • javascript 客户端启动,请求从找到的版本开始“观看”找到的工件历史记录(较旧的更改并不有趣)
  • 服务器进程记录该请求并持续检查和/或发送历史记录
  • 历史条目可能包含简单的通知“工件 x 已更改,客户端请请求” data”允许客户端独立轮询或完整数据集“artifact x 已更改为值 foo”
  • javascript artifact-updater 会在得知新值已更新后立即获取新值。它执行新的 ajax 请求或由 javascript 客户端提供数据。
  • 页面 DOM 内容已更新,用户可选择收到通知。历史观察仍在继续。

情况 2:现在进行提交:

  • 工件提交者从用户输入中知道所需的新值,并向服务器发送更改请求 服务器
  • 端互斥体已获取
  • 服务器接收到“嘿,我知道版本 123 中的工件 x 的状态,让我将其设置为请值 foo。”
  • 如果工件 x 的服务器端版本等于(不能小于)123,则接受新值,并生成新版本 id 124。
  • 新的状态信息“更新到版本 124”和可选的新值 foo 被放置在工件 x 的环形缓冲区(变更日志/历史记录)的开头,
  • 服务器端互斥体被释放,
  • 请求工件提交者很高兴收到提交确认以及新值ID。
  • 同时,服务器端服务器组件不断轮询/推送环形缓冲区到连接的客户端。所有监视工件 x 缓冲区的客户端都将在其通常的延迟内获取新的状态信息和值(请参见情况 1。)

情况 3:对于冲突:

  • 工件提交者从用户输入中知道所需的新值,并向服务器发送更改请求
  • 与此同时,另一个用户成功更新了相同的工件(参见案例 2),但由于各种延迟,我们的其他用户还不知道这一点。
  • 因此,获取服务器端互斥体(或等待,直到“更快”的用户提交其更改)
  • 服务器收到“嘿,我知道版本 123 中的工件 x 的状态,让我将其设置为值 foo”。
  • 在服务器端,工件 x 的版本现在已经是 124。发出请求的客户端无法知道他将覆盖的值。
  • 显然,服务器必须拒绝更改请求(不包括上帝干预的覆盖优先级),释放互斥锁,并足够好地将新版本 ID 和新值直接发送回客户端。
  • 面对被拒绝的提交请求和请求更改的用户还不知道的值,JavaScript 工件提交者会调用冲突解决程序,向用户显示并向用户解释问题。
  • 智能冲突解决程序 JS 向用户提供一些选项,允许用户再次尝试更改该值。
  • 一旦用户选择了他认为正确的值,该过程就会从情况 2 开始(如果其他人更快,则再次从情况 3 开始)

。可扩展性

HTTP 轮询与 HTTP“推送”

  • 轮询会创建请求,每秒 1 个、每秒 5 个,无论您认为什么是可接受的延迟。如果您没有将您的(Apache?)和(php?)配置得足够好以成为“轻量级”启动器,这对您的基础设施来说可能相当残酷。需要优化服务器端的轮询请求,使其运行时间远小于轮询间隔的长度。将运行时间一分为二很可能意味着将整个系统负载降低多达 50%,
  • 通过 HTTP 推送(假设 webworkers 距离太远而无法支持它们)将要求您为每个用户提供一个 apache/lighthttpd 进程一直。为每个进程保留的驻留内存和系统总内存将是您将遇到的一个非常确定的扩展限制。减少连接的内存占用是必要的,并限制每个中完成的连续 CPU 和 I/O 工作量(您需要大量的睡眠/空闲时间)

后端扩展

  • 忘记数据库和文件系统,您将需要某种基于共享内存的后端来进行频繁轮询(如果客户端不直接轮询,那么每个正在运行的服务器进程都会这样做)
  • 如果您使用内存缓存,您可以更好地扩展,但它仍然很昂贵
  • 用于提交的互斥体即使您想要多个前端服务器来进行负载平衡,也必须在全球范围内工作。

前端缩放

  • 无论您是轮询还是接收“推送”,都尝试一步获取所有观看工件的信息。

“创造性”调整

  • 如果客户端正在轮询并且许多用户倾向于观看相同的工件,您可以尝试将这些工件的历史记录作为静态文件发布,允许 apache 缓存它,但当工件发生更改时在服务器端刷新它。这使得 PHP/memcache 不再参与一些请求。 Lighthttpd 在提供静态文件方面非常有效。
  • 使用像 cotendo.com 这样的内容交付网络将工件历史记录推送到那里。推送延迟会更大,但可扩展性是一个梦想,
  • 可以编写一个用户使用 java 或 flash(?) 连接到的真实服务器(不使用 HTTP)。您必须在一个服务器线程中为许多用户提供服务。通过打开的套接字循环,执行(或委派)所需的工作。可以通过分叉进程或启动更多服务器进行扩展。不过,互斥体必须保持全局唯一。
  • 根据负载场景,按工件 ID 范围对前端和后端服务器进行分组。这将允许更好地使用持久内存(没有数据库拥有所有数据),并且可以扩展互斥。不过,您的 JavaScript 必须同时维护与多个服务器的连接。

好吧,我希望这可以成为您自己想法的开始。我相信还有很多更多的可能性。
我非常欢迎对这篇文章提出任何批评或改进,维基已启用。

克里斯托夫·斯特拉森

Overview:

  • Intro
  • Server architecture
  • Client architecture
  • Update case
  • Commit case
  • Conflict case
  • Performance & scalability

Hi Raynos,

I will not discuss any particular product here. What others mentioned is a good toolset to have a look at already (maybe add node.js to that list).

From an architectural viewpoint, you seem to have the same problem that can be seen in version control software. One user checks in a change to an object, another user wants to alter the same object in another way => conflict. You have to integrate users changes to objects while at the same time being able to deliver updates timely and efficiently, detecting and resolving conflicts like the one above.

If I was in your shoes I would develop something like this:

1. Server-Side:

  • Determine a reasonable level at which you would define what I'd call "atomic artifacts" (the page? Objects on the page? Values inside objects?). This will depend on your webservers, database & caching hardware, # of user, # of objects, etc. Not an easy decision to make.

  • For each atomic artifact have:

    • an application-wide unique-id
    • an incrementing version-id
    • a locking mechanism for write-access (mutex maybe)
    • a small history or "changelog" inside a ringbuffer (shared memory works well for those). A single key-value pair might be OK too though less extendable. see http://en.wikipedia.org/wiki/Circular_buffer
  • A server or pseudo-server component that is able to deliver relevant changelogs to a connected user efficiently. Observer-Pattern is your friend for this.

2. Client-Side:

  • A javascript client that is able to have a long-running HTTP-Connection to said server above, or uses lightweight polling.

  • A javascript artifact-updater component that refreshes the sites content when the connected javascript client notifies of changes in the watched artifacts-history. (again an observer pattern might be a good choice)

  • A javascript artifact-committer component that may request to change an atomic artifact, trying to acquire mutex lock. It will detect if the state of the artifact had been changed by another user just seconds before (latancy of javascript client and commit process factors in) by comparing known clientside artifact-version-id and current serverside artifact-version-id.

  • A javascript conflict-solver allowing for a human which-change-is-the-right decision. You may not want to just tell the user "Someone was faster than you. I deleted your change. Go cry.". Many options from rather technical diffs or more user-friendly solutions seem possible.

So how would it roll ...

Case 1: kind-of-sequence-diagram for updating:

  • Browser renders page
  • javascript "sees" artifacts which each having at least one value field, unique- and a version-id
  • javascript client gets started, requesting to "watch" the found artifacts history starting from their found versions (older changes are not interesting)
  • Server process notes the request and continuously checks and/or sends the history
  • History entries may contain simple notifications "artifact x has changed, client pls request data" allowing the client to poll independently or full datasets "artifact x has changed to value foo"
  • javascript artifact-updater does what it can to fetch new values as soon as they become known to have updated. It executes new ajax requests or gets feeded by the javascript client.
  • The pages DOM-content is updated, the user is optionally notified. History-watching continues.

Case 2: Now for committing:

  • artifact-committer knows the desired new value from user input and sends a change-request to the server
  • serverside mutex is acquired
  • Server receives "Hey, I know artifact x's state from version 123, let me set it to value foo pls."
  • If the Serverside version of artifact x is equal (can not be less) than 123 the new value is accepted, a new version id of 124 generated.
  • The new state-information "updated to version 124" and optionally new value foo are put at the beginning of the artifact x's ringbuffer (changelog/history)
  • serverside mutex is released
  • requesting artifact committer is happy to receive a commit-confirmation together with the new id.
  • meanwhile serverside server component keeps polling/pushing the ringbuffers to connected clients. All clients watching the buffer of artifact x will get the new state information and value within their usual latency (See case 1.)

Case 3: for conflicts:

  • artifact committer knows desired new value from user input and sends a change-request to the server
  • in the meanwhile another user updated the same artifact successfully (see case 2.) but due to various latencies this is yet unknown to our other user.
  • So a serverside mutex is acquired (or waited on until the "faster" user committed his change)
  • Server receives "Hey, I know artifact x's state from version 123, let me set it to value foo."
  • On the Serverside the version of artifact x now is 124 already. The requesting client can not know the value he would be overwriting.
  • Obviously the Server has to reject the change request (not counting in god-intervening overwrite priorities), releases the mutex and is kind enough to send back the new version-id and new value directly to the client.
  • confronted with a rejected commit request and a value the change-requesting user did not yet know, the javascript artifact committer refers to the conflict resolver which displays and explains the issue to the user.
  • The user, being presented with some options by the smart conflict-resolver JS, is allowed another attempt to change the value.
  • Once the user selected a value he deems right, the process starts over from case 2 (or case 3 if someone else was faster, again)

Some words on Performance & Scalability

HTTP Polling vs. HTTP "pushing"

  • Polling creates requests, one per second, 5 per second, whatever you regard as an acceptable latency. This can be rather cruel to your infrastructure if you do not configure your (Apache?) and (php?) well enough to be "lightweight" starters. It is desirable to optimize the polling request on the serverside so that it runs for far less time than the length of the polling interval. Splitting that runtime in half might well mean lowering your whole system load by up to 50%,
  • Pushing via HTTP (assuming webworkers are too far off to support them) will require you to have one apache/lighthttpd process available for each user all the time. The resident memory reserved for each of these processes and your systems total memory will be one very certain scaling limit that you will encounter. Reducing the memory footprint of the connection will be necessary, as well as limiting the amount continuous CPU and I/O work done in each of these (you want lots of sleep/idle time)

backend scaling

  • Forget database and filesystem, you will need some sort of shared memory based backend for the frequent polling (if the client does not poll directly then each running server process will)
  • if you go for memcache you can scale better, but its still expensive
  • The mutex for commits has to work globaly even if you want to have multiple frontend servers to loadbalance.

frontend scaling

  • regardless if you are polling or receiving "pushes", try to get information for all watched artifacts in one step.

"creative" tweaks

  • If clients are polling and many users tend to watch the same artifacts, you could try to publish the history of those artifacts as a static file, allowing apache to cache it, nevertheless refreshing it on the serverside when artifacts change. This takes PHP/memcache out of the game some for requests. Lighthttpd is verry efficent at serving static files.
  • use a content delivery network like cotendo.com to push artifact history there. The push-latency will be bigger but scalability's a dream
  • write a real server (not using HTTP) that users connect to using java or flash(?). You have to deal with serving many users in one server-thread. Cycling through open sockets, doing (or delegating) the work required. Can scale via forking processes or starting more servers. Mutexes have to remain globaly unique though.
  • Depending on load scenarios group your frontend- and backend-servers by artifact-id ranges. This will allow for better usage of persistent memory (no database has all the data) and makes it possible to scale the mutexing. Your javascript has to maintain connections to multiple servers at the same time though.

Well I hope this can be a start for your own ideas. I am sure there are plenty more possibilities.
I am more than welcoming any criticism or enhancements to this post, wiki is enabled.

Christoph Strasen

佼人 2024-10-21 12:52:22

我知道这是一个老问题,但我想我只是插话一下。

OT(操作转换)< /a> 似乎很适合您对并发和一致的多用户编辑的要求。这是Google 文档中使用的技术(也在 Google Wave 中使用):

有一个基于 JS 的库用于使用操作转换 - ShareJS (http://sharejs .org/),由 Google Wave 团队的一名成员编写。

如果您愿意,可以构建完整的 MVC Web 框架 - DerbyJS (http://derbyjs.com/) ShareJS 可以为您完成这一切。

它使用 BrowserChannel 在服务器和客户端之间进行通信(我相信 WebSockets 支持应该正在开发中 - 它之前是通过 Socket.IO 提供的,但由于开发人员的 Socket.io 问题而被删除)初学者文档是然而,目前有点稀疏。

I know this is an old question, but I thought I'd just chime in.

OT (operational transforms) seem like a good fit for your requirement for concurrent and consistent multi-user editing. It's a technique used in Google Docs (and was also used in Google Wave):

There's a JS-based library for using Operational Transforms - ShareJS (http://sharejs.org/), written by a member from the Google Wave team.

And if you want, there's a full MVC web-framework - DerbyJS (http://derbyjs.com/) built on ShareJS that does it all for you.

It uses BrowserChannel for communication between the server and clients (and I believe WebSockets support should be in the works - it was in there previously via Socket.IO, but was taken out due to the developer's issues with Socket.io) Beginner docs are a bit sparse at the moment, however.

长安忆 2024-10-21 12:52:22

我会考虑为每个数据集添加基于时间的修改标记。因此,如果您要更新数据库表,您将相应地更改修改后的时间戳。使用 AJAX,您可以将客户端的修改时间戳与数据源的时间戳进行比较 - 如果用户落后,则更新显示。类似于此网站定期检查问题以查看在您输入答案时是否有其他人回答的方式。

I would consider adding time-based modified stamp for each dataset. So, if you're updating db tables, you would change the modified timestamp accordingly. Using AJAX, you can compare the client's modified timestamp with the data source's timestamp - if the user is ever behind, update the display. Similar to how this site checks a question periodically to see if anyone else has answered while you're typing an answer.

浅浅 2024-10-21 12:52:22

一旦对数据库进行了更改,您就需要使用推送技术(也称为 Comet 或反向 Ajax)将更改传播给用户。目前可用的最佳技术似乎是 Ajax 长轮询,但并非所有浏览器都支持它,因此您需要后备方案。幸运的是,已经有解决方案可以为您处理这个问题。其中包括:orbited.org 和已经提到的 socket.io。

将来会有一种更简单的方法来做到这一点,称为 WebSockets,但目前还不确定该标准何时准备好迎接黄金时段,因为该标准的当前状态存在安全问题。

数据库中不应存在新对象的并发问题。但是,当用户编辑对象时,服务器需要有一些逻辑来检查该对象是否同时被编辑或删除。如果对象已被删除,解决方案也很简单:只需放弃编辑即可。

但当多个用户同时编辑同一个对象时,就会出现最困难的问题。如果用户 1 和 2 同时开始编辑对象,他们都会对相同的数据进行编辑。假设用户 1 所做的更改首先发送到服务器,而用户 2 仍在编辑数据。然后您有两个选择:您可以尝试将用户 1 的更改合并到用户 2 的数据中,或者您可以告诉用户 2 他的数据已过期,并在他的数据发送到服务器后立即向他显示错误消息。后者在这里不是非常用户友好的选项,但前者很难实现。

第一次真正做到这一点的少数实现之一是 EtherPad,它被谷歌。我相信他们随后在 Google Docs 和 Google Wave 中使用了 EtherPad 的一些技术,但我不能确定。 Google 还开源了 EtherPad,所以也许值得一看,具体取决于您想要做什么。

做这种同时编辑的事情确实不容易,因为由于延迟,不可能在网络上进行原子操作。也许这篇文章将帮助您了解有关该主题的更多信息。

You need to use push techniques (also known as Comet or reverse Ajax) to propagate changes to the user as soon as they are made to the db. The best technique currently available for this seems to be Ajax long polling, but it isn't supported by every browser, so you need fallbacks. Fortunately there are already solutions that handle this for you. Among them are: orbited.org and the already mentioned socket.io.

In the future there will be an easier way to do this which is called WebSockets, but it isn't sure yet when that standard will be ready for prime time as there are security concerns about the current state of the standard.

There shouldn't be concurrency problems in the database with new objects. But when a user edits an object the server needs to have some logic that checks whether the object has been edited or deleted in the meantime. If the object has been deleted the solution is, again, simple: Just discard the edit.

But the most difficult problem appears, when multiple users are editing the same object at the same time. If User 1 and 2 start editing an object at the same time, they will both make their edits on the same data. Let's say the changes User 1 made are sent to the server first while User 2 is still editing the data. You then have two options: You could try to merge User 1's changes into the data of User 2 or you could tell User 2 that his data is out of date and display him an error message as soon as his data gets send to the server. The latter isn't very user friendly option here, but the former is very hard to implement.

One of the few implementations that really got this right for the first time was EtherPad, which was acquired by Google. I believe they then used some of EtherPad's technologies in Google Docs and Google Wave, but I can't tell that for sure. Google also opensourced EtherPad, so maybe that's worth a look, depending on what you're trying to do.

It's really not easy to do this simultaneously editing stuff, because it's not possible to do atomic operations on the web because of the latency. Maybe this article will help you to learn more about the topic.

叹梦 2024-10-21 12:52:22

尝试自己编写所有这些内容是一项艰巨的工作,而且很难做到正确。一种选择是使用一个框架,该框架旨在使客户端与数据库以及彼此之间实时保持同步。

我发现 Meteor 框架在这方面做得很好(http://docs.meteor.com/#reactivity)。

“Meteor 采用了反应式编程的概念。这意味着您可以用简单的命令式风格编写代码,只要代码所依赖的数据发生变化,结果就会自动重新计算。”

“这种简单的模式(反应式计算 + 反应式数据源)具有广泛的适用性。程序员无需编写取消订阅/重新订阅调用并确保它们在正确的时间被调用,从而消除了整个数据传播代码类,否则这些代码会阻塞您的数据传播代码。具有容易出错逻辑的应用程序。”

Trying to write all this yourself is a big job, and it's very difficult to get it right. One option is to use a framework that's built to keep clients in sync with the database, and with each other, in realtime.

I've found that the Meteor framework does this well (http://docs.meteor.com/#reactivity).

"Meteor embraces the concept of reactive programming. This means that you can write your code in a simple imperative style, and the result will be automatically recalculated whenever data changes that your code depends on."

"This simple pattern (reactive computation + reactive data source) has wide applicability. The programmer is saved from writing unsubscribe/resubscribe calls and making sure they are called at the right time, eliminating whole classes of data propagation code which would otherwise clog up your application with error-prone logic."

或十年 2024-10-21 12:52:22

我不敢相信没有人提到过 Meteor。这肯定是一个新的、不成熟的框架(并且只正式支持一个数据库),但它需要像海报所描述的那样,完成所有繁重的工作和多用户应用程序的思考。事实上,您不能不构建一个多用户实时更新应用程序。以下是一个快速总结:

  • 一切都在 Node.js(JavaScript 或 CoffeeScript)中,因此您可以在客户端和服务器之间共享验证等内容。
  • 它使用 websockets,但可以回退到较旧的浏览器。
  • 它专注于本地对象的即时更新(即 UI 感觉敏捷),并将更改发送到后台的服务器。仅允许原子更新以使混合更新更简单。服务器上拒绝的更新将被回滚。
  • 作为奖励,它可以为您处理实时代码重新加载,并且即使应用程序发生根本变化,也可以保留用户状态。

Meteor 非常简单,我建议您至少看一下它,以获取可以借鉴的想法。

I can't believe that nobody has mentioned Meteor. It's a new and immature framework for sure (and only officially supports one DB), but it takes all the grunt work and thinking out of a multi-user app like the poster is describing. In fact, you can't NOT build a mult-user live-updating app. Here's a quick summary:

  • Everything is in node.js (JavaScript or CoffeeScript), so you can share stuff like validations between the client and server.
  • It uses websockets, but can fall back for older browsers
  • It focuses on immediate updates to local object (i.e. the UI feels snappy), with changes sent to the server in the background. Only atomic updates are allowed to make mixing updates simpler. Updates rejected on the server are rolled back.
  • As a bonus, it handles live code reloads for you, and will preserves user state even when the app changes radically.

Meteor is simple enough that I would suggest you at least take a look at it for ideas to steal.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文