管理页面上的 AJAX 控件加载顺序

发布于 2024-11-17 09:32:11 字数 961 浏览 6 评论 0原文

我认为我在使用 AJAX Web 应用程序时遇到了竞争条件。我正在使用 JQuery 1.4.4 来处理 AJAX 请求。

我有一个菜单控件/类,用户单击它即可显示用于操作数据的控件。单击菜单可以显示多个控件,这些控件彼此独立地初始化并以不同的速度加载,并以不可预测的顺序变得可用(我猜是 AJAX 中的 A...)。

这些控件相互交互,例如,在一个控件中选择一个项目会将其添加到另一个控件中。通过使用 JQuery 触发源控件中的事件并绑定到目标控件中的该事件来发生交互。问题似乎是,当您在所有控件完成初始化之前开始与控件交互时,可能会导致问题。例如,添加项目似乎在源控件中有效,而目标控件仍在加载,但加载后不会显示添加的项目。我认为这是因为添加项目请求被触发并完成,而加载仍在发生,然后覆盖任何更改。

控件设计的目的是使它们尽可能相互独立,并且如果可能的话,不要直接调用彼此的方法和属性。相同的控件在各种上下文中使用,并且不知道同时显示的其他控件是什么。有一个中心类控制控件的显示和隐藏——菜单。

任何人都可以建议一种方法,使控件/类保持松散耦合,但能够管理它们之间的依赖关系并知道何时可以允许交互?

我的一些想法如下。对这些或进一步建议的任何想法都表示赞赏。

  1. 菜单类可以维护某种标志,指示所有控件何时初始化 - 这将基于在每个控件成功加载时递增的递增计数。这是唯一一个知道当前正在使用的控件的类,但它是以一种通用的方式完成的,其中控件将自身传递进去以进行显示。

  2. 加载事件由每个控件触发,并且该上下文中显示的其他控件绑定到彼此的加载事件。控件需要更多地了解它们正在使用的上下文,以便它们知道它们何时是最后一个加载的控件,从而准备好与页面进行交互。

  3. 实现页面加载后执行的请求队列。但这看起来有点太同步了。

  4. 升级到 JQuery 1.6.2 正在考虑中,但尚未计划。由于控件的通用/匿名性质,我不确定 deferred 是否是正确的选项。

感谢您的帮助

I think I am experiencing race conditions with an AJAX web application. I am using JQuery 1.4.4 to handle the AJAX requests.

I have a menu control/class that the user clicks to display controls for manipulating data. Clicking the menu can display multiple controls which initialise independently of each other and load at different speeds and become available in an unpredictable order (the A in AJAX I guess...).

The controls interact with each other, for example selecting an item in one control adds it to another. The interaction happens by triggering the event in the source control using JQuery and binding to that event in the destination control. The issue seems to be that when you start interacting with a control before all controls are finished initialising you can cause problems. For example, adding an item appears to have worked in the source control whilst the destination control is still loading but when it has loaded it doesn't show the added item. I think that this is because the add item request is fired and completed whilst the load is still happening which then overwrites any changes.

The intention in the design of the controls was to keep them as independent of each other as possible and for them to not call directly into each other's methods and properties if possible. The same controls are used in a variety of contexts and are unaware of what other controls are being displayed at the same time. There is a central class that controls the display and hiding of the controls - the menu.

Could anyone suggest an approach that would keep the controls / classes loosely coupled but be able to manage the dependencies between them and to know when it is OK to allow interaction?

A few ideas that I have are below. Any thoughts on these or further suggestions are appreciated.

  1. The menu class could maintain some kind of flag that indicates when all controls are initialised - this would be based say on an incrementing count that is incremented on the successful load of each control. This is the only class that is aware of the controls that are currently in use but it is done in a generic way where the controls pass themselves in to be shown.

  2. Loaded events are fired by each control and other controls being shown in that context bind to each other's loaded event. The controls would need to know more about the context in which they are being used though so that they know when they were the last control to be loaded and thus the page was ready to be intereacted with.

  3. Implement a queue of requests that get executed once the page is loaded. This seems a little too synchronous though.

  4. Upgrading to JQuery 1.6.2 is on the cards for consideration but not scheduled. I am not sure if deferred would be the correct option here anyway due to the generic / anonymous nature of the controls.

Thanks for your help

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

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

发布评论

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

评论(2

不喜欢何必死缠烂打 2024-11-24 09:32:11

在 2007/08 年,我曾经参与过一个主要由 Ajax 驱动的项目,这意味着几个页面在被另一个页面重新加载之前会进行相当多的页面交互和处理。主要思想是应用程序(或页面)有一个中央控制器,可以将各个控件相互解耦,同时提供控件内部通信的功能。典型的页面场景是它显示用户与之交互的树状结构(具有不同类型的各种项目)。基于此交互,其他控件(如主列表或详细信息列表或创建/更改表单等)被显示并与之交互。

反正。整个事情是如何进行的?

控制内部通信 - 预定义的有限事件集

我编写了一种 javascript 页面控制器,以便每个页面都与其交互。我还介绍了一组预定义事件。大多数这些事件都有一个关于项目/组的附加元数据,无论它们是什么。应用程序中有大约 50 个不同的预定义事件。每个事件都由以下定义:

  • 特定类型:即。 ActivityGroupEvent
  • 事件操作:选择、选定、创建、创建、删除、删除、更改、更改、删​​除、删除、丢弃、丢弃、无关紧要的
  • 可选元数据:元数据主要与此事件所属的项目相关关于

控件解耦 - 中央事件处理

所有事件处理(与控件的内部工作无关,如单击事件等)都是通过页面控制器处理的。

每个控件(当它创建自己时)都有一个初始化函数,该函数自动订阅特定的事件类型(即:订阅选择项事件的项目详细信息视图控件)。事件订阅使得控件之间完全独立成为可能。因此,当发生选择项事件时,订阅的控件会收到该事件,无论它源自何处。是从主视图还是左侧树中也可能显示了单独的项目。

动态页面控件 - 按需创建控件

页面处理还初始化事件按需控件加载。因此,当引发特定事件时,页面控制器 Ajax 在事件分派之前加载特定控件。控制自己然后照顾自己的一生。但它们都包含(继承相同的 javascript 原型)功能来通知页面控制器它们的删除,因此页面控制器在需要时重新加载它们。

为什么事件动作对喜欢删除/删除?

这个想法是,当用户单击删除项目图标(例如)时,会在页面级别引发删除事件。然后,页面控制器将此事件分派给处理该事件的订阅控件。

示例:当前页面显示左树、主视图和详细视图。

  1. 用户单击树控件中的删除项目。
  2. 此特定控件会在页面级别上使用项目元数据引发删除项目事件(调用pageController.raise(...))。
  3. 页面控制器加载一个删除确认控件(这个控件不会发起 Ajax 请求,因为它不需要获取任何服务器数据)
  4. 页面控制器然后将删除项目事件分派给这个加载/创建的控件
  5. 然后用户与其交互并确认删除。
  6. 控件负责服务器上的项目删除(Ajax 请求)
  7. 删除完成后,此删除确认控件会在页面级别引发已删除项目事件。
  8. 页面控制器将其分派给所有订阅的控件(在本例中为树视图、主视图和详细信息视图),这些控件通过执行自己的操作来消耗此事件(大多数控件会从列表中删除该项目(不一定发出 Ajax 请求) )
  9. 删除确认控件引发已删除项目事件后,它也会自行销毁并通知页面控制器,以便它知道在引发某个事件时必须再次重新创建,这

有什么好处 。使用页面控制器

需要什么 ?关心几件事:

  • 所有控件都可以使用的集中页面“脏状态”处理 - 控件可以声明
    他们自己是“脏”,他们还可以在启动某些操作之前检查页面是否脏
    操作(即菜单将在导航到新页面之前检查脏状态);当一个控件想要通知用户页面脏了(或者更好地说他们无法执行他们想要的操作)时,页面控制器提供了一个功能来统一通知用户脏状态;每个控件(当声明脏状态时)都有可能包含一个描述其脏状态的字符串(即“必须保存或丢弃更改项形式。”)
  • 控制解耦,同时仍然通过事件引发和分派提供控件间通信 –控件之间不知道彼此;只有页面控制器知道这些控件,因此负责它们的创建、初始化、页面级事件处理和处置;
  • 控制器操作 – 类似于控制事件处理程序,但这些操作由
    在事件被分派给接收者之前(即,当
    用户选择一个项目,控制器执行一个操作以在运行之前动态创建详细信息表单
    向其分派事件——如果它在初始化周期中注册了该事件);

这对您的情况有何帮助?

这里的主要思想是,您需要控制解耦,同时还可以集中引发事件(您是否需要复杂的事件列表,或者只是一些简单的预定义集,取决于您和您的业务流程)。这使得控件可以异步加载并独立交互。页面控制器(我这样称呼它)将在控件初始化后负责事件调度。因此它可以将他们推迟到适当的时刻。

可以使用现有的库吗?

哦最后一件事。我忘了提到我们使用 ExtJS 来实现丰富的客户端视觉控制。但我们已经扩展了其中的很多,也编写了很多我们自己的。特别是我们需要所有这些页面级交互性。现在有一些 JavaScript 库可以在这方面帮助你,但我不能说,因为我对它们完全不熟悉。但由于他们的名字适用,他们确实提供了一些页面级别的控制。这些将是 BackboneJavascriptMVC。但由您检查它们是否提供适当的功能。

附录 - 页面控制器公共函数

  • void setDirty(object sender[, string description]) – 每个控件在其状态已更改或面临更改时都必须调用此方法;描述用于以文本方式描述控件的脏状态,并在向用户显示消息时使用(在 isPageDirty 函数中使用)
  • voidclearDirty(object sender) – 用户保存或丢弃数据,控件必须调用此方法以允许其他控件执行其“清理页面功能”;
  • bool isPageDirty([bool displayMessage]) – 在控件执行一些“清理页面功能”之前,它们必须调用此函数;如果他们提供一个值为true的参数,如果页面脏了,控制器将自动向用户显示一条消息(保存或丢弃);
  • void createAction(type eventType, enum actionType, function func[, bool runOnce]) – 当您实现新控制器时,您可以使用此函数为自己准备操作;
  • void removeAction(type eventType, enum actionType, function func) – 这将删除之前准备的操作;
  • void registerReceiver(type eventType, enum actionType, object receive, function func) – 控件使用此函数来注册自己以接收特定事件;
  • void unregisterReceiver(type eventType, enum actionType, object receive, function func) – 控件在被销毁之前必须取消注册;
  • void raiseEvent(enum actionType, object eventInstance) – 控件在触发页面级事件时调用此方法;
  • voidinitialize() – 当您从 ControllerBase 类继承新的页面控制器时,您必须实现此方法。页面加载时会自动调用;你
    通常应该在其中设置初始页面状态(创建需要在开始时创建的所有控件等)

In 2007/08 I used to work on a project which was heavily Ajax powered which means that several pages did quite some page interaction and processing before being reloaded by a different page. The main idea was that the application (or pages) had a central controller that decoupled individual controls from each other while providing the functionality for control inter communication. A typical page scenario was that it displayed a tree-like structure (with various items of different types) that user interacted with. Based on this interaction other controls (like master list or details list or create/change form etc.) was displayed and interacted with.

Anyway. How did the whole thing work?

Control inter-communication - predefined finite set of events

I've written a kind of javascript page controller so every page interacted with it. I also introduced a set of predefined events. Most of these events had an attached metadata about the item/group whatever they were about. There were about 50 different predefined events in the application. Each event was defined by these:

  • particular type: ie. ActivityGroupEvent
  • event action: select, selected, create, created, delete, deleted, change, changed, delete, deleted, discard, discarded, insignificant
  • optional metadata: metadata was mostly related to the item that this event was about

Control decoupling - central event handling

All event handling (that wasn't related to control's internal workings like click events etc) were handled through page controller.

Every control (when it created itself) had an initialization function that automatically subscribed to particular event types (ie: item details view control subscribed to select item event). Event subscription made it possible for controls to be completely independent from each other. So when there was a select item event raised a subscribed control received it no matter where it originated from. Was it from a master view or the left tree that may have also displayed individual items.

Dynamic page controls - control creation on demand

Page processing also initialized event on demand control loading. So when a particular event was raised, page controller Ajax loaded particular controls prior to event dispatching. Controls themselves then took care of their life time. But they all included (inherited the same javascript prototype) functionality to inform page controller of their removal, so page controller re-loaded them when needed.

Why event action couples like delete/deleted?

The idea is, that when a user clicked a delete item icon (for instance) a delete event was raised on the page level. Page controller than dispatched this event to subscribed controls that processed it.

Example: currently page displays left tree, master view and details view.

  1. User clicks delete item in the tree control.
  2. This particular control raises delete item event with item metadata on the page level (calls pageController.raise(...)).
  3. Page controller loads a delete confirmation control (well this one wouldn't initiate an Ajax request since it doesn't need to get any server data)
  4. Page controller then dispatches delete item event to this loaded/created control
  5. User then interacts with it and confirms deletion.
  6. Control takes care of item deletion on the server (Ajax request)
  7. After deletion was completed this delete confirmation control raises a deleted item event on the page level.
  8. Page controller dispatches it to all subscribed controls (in this case that would be the tree, master and details view) that consume this event by doing their own stuff (most of them would remove the item from their list (not necessarily issuing an Ajax request)
  9. After delete confirmation control raised deleted item event it also destrys itself and informs page controller about it so it knows it will have to recreate is again when a certain event will be raised.

What're the benefits of using a page controller?

Page controller takes care of several things:

  • Centralised page »dirty state« handling that all controls can use – controls can claim
    themselves as »dirty« and they can also check if page is dirty before initiating certain
    actions (i.e. menu will check dirty state before navigating to a new page); When a control wanted to inform user of the page being dirty (or better said that they can't execute the action they wanted) page controller provides a function that uniformly informs user of dirty state; Each control (when claiming dirty state) has the possibility of including a string that describes its dirty state (ie. "Change item form must be saved or discarded.")
  • Control decoupling while still providing inter-control communication through event raising and dispatching – controls are not aware of each other; only page controller knows of these controls and is therefore responsible for their creation, initialization, page level event handling and disposal;
  • Controller actions – similar to control event handlers, but these are executed by the
    page controller on certain events before event gets dispatched to receivers (i.e. when a
    user selects an item, controller executes an action to create detail form on the fly before
    dispatching event to it – if it registers for this event in its initialization cycle);

How can this be helpful in your case?

The main idea here is that you need control decoupling that also centrally raise events (whether you will need sophisticated list of events or just some simple predefined set is up to you and your business process). This makes it possible that controls may be loaded asynchronously and independently interacted with as well. Page controller (as I called it) will take care of event dispatching after the control will be initialized. So it can delay them up to the appropriate moment.

Can existing libraries be used?

Oh one last thing. I forgot to mention that we used ExtJS for rich client side visual controls. But we've extended lots of them and written lots of our own as well. Especially we needed all this page-level interactivity. Nowadays there are javascript libraries that may help you in this regard, but I can't say since I'm completely unfamiliar with them. But since their name applies they do provide some controlling on page level. And these would be Backbone and JavascriptMVC. But it's up to you to check whether they provide appropriate functionality or not.

Appendix - page controller public functions

  • void setDirty(object sender[, string description]) – every control must call this method when its state has been changed or are exposed to change; Description is used to textually describe control's dirty state and is used when displaying a message to the user (used in isPageDirty function)
  • void clearDirty(object sender) – after user saved or discarded data, controls must call this method to allow other controls to execute their »clean page functionality«;
  • bool isPageDirty([bool displayMessage]) – before controls execute some »clean page functionality« they must call this function; if they provide a parameter of value true, controller will automaticaly display a message to the user (save or discard) if the page is dirty;
  • void createAction(type eventType, enum actionType, function func[, bool runOnce]) – when you implement a new controller you prepare yourself actions using this function;
  • void removeAction(type eventType, enum actionType, function func) – this will remove a previously prepared action;
  • void registerReceiver(type eventType, enum actionType, object receiver, function func) – controls use this function to register themselves for particular events receiving;
  • void unregisterReceiver(type eventType, enum actionType, object receiver, function func) – controls must unregister themselves before they are destroyed;
  • void raiseEvent(enum actionType, object eventInstance) – controls call this method when they fire a page-level event;
  • void initialize() – when you inherit a new page controller from a ControllerBase class you have to implement this method. It will automatically get called when page loads; you
    should normally set initial page state in it (create all controls that need to be created at the beginning etc.)
方觉久 2024-11-24 09:32:11

我会选择菜单类选项,其中感兴趣的控件自行注册,并且该类仅指示何时加载所有已注册的控件(递增计数选项可能是正确的选项)。

您的优势在于,这可以保持控件独立,允许添加其他控件等,这是您似乎正在尝试做的事情的一个重要方面。

我认为已经考虑或完成的另一个想法是仅绑定在就绪文档上。这意味着只有当页面上的所有控件都加载时,绑定才可用。是否有某种原因表明这不合适或不起作用?

I would go for the menu class option, where controls of interest register themselves, amd the class simply indicates when all registered controls are loaded ( the incrementing count option is probably the right one ).

You have the advantage that this keeps the controls independent, allows for other contrls to be added etc, which is an important aspect of what you seem to be trying to do.

The other idea, which I presume has been considered or done, is to only bind on the document onready. This means that the bindings will only be available when all of the contorls on the page are loaded. Is there some reason that this is not appropriate or does not work?

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