您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 网站教程 > AJAX教程 >
    为AJAX实现互斥(2)
    时间:2018-11-07 19:13 来源: 作者: 浏览:收藏 挑错 推荐 打印

      23  // constructor logic    24  this.c    = cmdObject;
        25  this.methodID = methodName;
        26  //(enter and number are "false" here)
        27  Mutex.Wait.add( this.c.id, this );
        28  this.enter  = true;
        29  this.number  = (new Date())。getTime();
        30  this.enter  = false;
        31  this.attempt( Mutex.Wait.first() );
        32 }
        Mutex类的基本逻辑是将每个新的Mutex实例放入主等待清单,然后将其在等待队列中启动。因为每次到达“队首”的尝试都需要等待(除了最后一次), 所以使用setTimeout来调度每次在当前尝试停止的位置启动的新尝试。到达队首时(见17行),便实现了互斥性访问;因此,可以调用临界区方法。执 行完临界区后,释放互斥性访问并从等待清单中移除Mutex实例(见20-21行)。
        Mutex构造函数(见23-31行)记录其Command对象和方法名参数,然后寄存在一个运行中临界区的稀疏数组中(Mutex.Wait),这通过 清单4中所示的Map类来实现。然后构造函数获得下一个编号,并在队尾开始排队。由于等待编号中的间隔或副本不存在问题,所以实际上使用当前的时间戳作为 下一个编号。
        attempt()方法将初始伪代码中的两个wait循环组合成一个单独的循环,该循环直到队首时才对临界区失效。该循环是一种忙碌-等待循环检测方式, 可以通过在setTimeout()调用中指定延迟量来终止该循环。由于setTimeout需要调用“无格式函数”,所以在第4-6行定义了静态帮助器 方法(Mutex.SLICE)。SLICE在主等待清单中查找指定的Mutex对象,然后调用其attempt()方法,用start参数指定到目前为 止其所获得的等待清单的长度。每次SLICE()调用都像获得了“一块CPU”。这种(通过setTimeout)适时释放CPU的协作方式令人想到协同 程序。
        清单4. 作为 Map数据结构实现的稀疏数组
        function Map() {
        this.map = new Object();
        // Map API
        this.add = function( k,o ){
        this.map[k] = o;
        }
        this.remove = function( k ){
        delete this.map[k];
        }
        this.get = function( k ){
        return k==null ? null : this.map[k];
        }
        this.first = function(){
        return this.get( this.nextKey() );
        }
        this.next = function( k ){
        return this.get( this.nextKey(k) );
        }
        this.nextKey = function( k ){
        for (i in this.map) {
        if ( !k ) return i;
        if (k==i) k=null; /*tricky*/
        }
        return null;
        }
        }
        富Internet应用程序集成
        由于Mutex所处理的线程(虚拟的或者非虚拟的)数量是动态变化的,所以可以确定一个基本事实:无法通过像浏览器为各个浏览器事件分配单独的线程那样的 方式来获得线程标识符。这里做了一个类似的假定,那就是每个完整的事件处理程序组成一个完整的临界区。基于这些假定,每个事件处理函数都可以转变成一个 command对象,并使用Mutex对其进行管理。当然,如果未将代码明确组织成事件处理函数,那么将需要重构。换句话说,不是直接在HTML事件属性 中进行逻辑编码(例如:onclick='++var'),而是调用事件处理函数(例如:onclick='FOO()'和function FOO(){++var;})。
        清单5. 使用了非同步事件处理程序的示例web页面
        <html>
        <script language="JavaScript">
        function newState(){
        if (XMLreq.readyState==4) processReply();
        }
        function requestData(){
        …set up asynchronous XML request…
        XMLreq.onreadystatechange = newState;
        …launch XML request…
        }
        function processReply(){
        var transformedData = …process data to HTML…
        OutputArea.innerHTML = transformedData + "<br>";
        }
        function clearArea(){
        OutputArea.innerHTML = "cleared<br>";
        }
        </script>
        <body onload="requestData();">
        <input type="button" value="clear" onclick="clearArea()">
        <div id="OutputArea"/>
        </body>
        </html>
        例如,假设有三个事件处理程序函数,它们操纵清单5所示的共用数据。它们处理页面加载事件、单击按钮事件和来自XML请求的应答事件。页面加载事件发出某 个异步请求来要求获取数据并指定请求-应答事件处理程序,该处理程序处理接收到的数据,并将其加载到共用数据结构。单击按钮事件处理程序也影响共用数据结 构。为了避免这些事件处理程序发生冲突,可以通过清单6所示的Mutex将它们转变成command并加以调用(假设JavaScript include文件mutex.js中包含Map和Mutex)。注意,虽然可以使用优美的类继承机制来实现Command子类,但是该代码说明了最简单 的方法,该方法仅需要全局变量NEXT_CMD_ID。
        清单6. 转化为同步事件处理程序的web页面
        <html>
        <script src="mutex.js"></script>
        <script language="JavaScript">
        function requestData (){
        new Mutex(new RequestDataCmd(),"go"); }
        function processReply(){
        new Mutex(new ProcessReplyCmd(),"go"); }
        function clearArea  (){
        new Mutex(new  ClearAreaCmd(),"go"); }
        function newState  (){
        if (XMLreq.readyState==4) processReply(); }
        var NEXT_CMD_ID = 0;
        function RequestDataCmd(){
        this.id = ++NEXT_CMD_ID;
        this.go = function(){
        …set up asynchronous XML request…
        XMLreq.onreadystatechange = NewState;
        …launch XML request…
        }
        }
        function ProcessReplyCmd(){
        this.id = ++NEXT_CMD_ID;
        this.go = function(){
        var transformedData = …process data to HTML…
        OutputArea.innerHTML = transformedData + "<br>";
        }
        }
        function ClearAreaCmd(){
        this.id = ++NEXT_CMD_ID;
        this.go = function(){
        OutputArea.innerHTML = "cleared<br>"; }
        }
        </script>
        <body onload="requestData();">
        <input type="button" value="clear" onclick="clearArea()">
        <div id="OutputArea"/>
        </body>
        </html>
        已经通过Mutex将这三个事件处理程序函数转变为调用它们的初始逻辑(当前都被预包装于command类中)。各个command类定义一个独特的标识符和一个包含临界区逻辑的方法,从而满足了command接口的要求。
        结束语
        借助于AJAX和RIA,构建复杂的动态用户界面的推动力正在促使开发人员使用先前与胖GUI客户端紧密联系的设计模式(例如:模型-视图-控制器)。随 着视图和控制器的定义模块化,且每一个都带有自己的事件和事件处理程序(除了共用数据模型),发生冲突的机率成倍提高。通过把事件处理逻辑封装到 Command类中,不仅可以使用Wallace变体,而且为提供丰富的撤消/重做功能、脚本编写界面和单元测试工具创造了条件。
        参考资料本文的示例代码可供浏览或下载。它包括了一些在本文中被省略的细节,比如web页面可以无需服务器连接而直接在浏览器中执行。 有一个可供浏览或下载的JavaScript示例框架(Gravy),它使用了本文中所涉及的技术,同时包括JsDoc文档。Gravy支持将所有浏览器中的应用程序功能以JavaScript方式实现。应用程序仅需要访问服务器来执行数据库CRUD操作。

    (责任编辑:12图资源库)