西西河

主题:【原创】Google Mail和XMLHTTPRequest -- 请尽量

共:💬14 🌺7 新:
分页树展主题 · 全看
  • 家园 【原创】Google Mail和XMLHTTPRequest

    用过Google Mail后,细心的同志会注意到其用户界面和其他的web应用的有些不同:更加流畅、快捷,就象native的桌面应用一样。虽然从状态条上可以看出浏览器在不断地和Google的服务器交换信息,但浏览器的页面似乎从来没有重新加载。更妙的是,居然可以根据地址簿自动补全收件人的地址。Google Suggest更是绝妙,简直就是实时地根据表单输入框中内容的变化来更新所推荐的检索关键字列表。

    在惊叹之余,大家一定会好奇,Google到底用了什么新技术?可在这浏览器还是以前的浏览器啊?Google也没让下载安装任何插件啊?

    其实,Google没有用任何“新”技术。在Google Mail、Google Maps和Google Suggest等应用中,把user experience推向一个新高度的是JavaScript和XMLHTTPRequest。

    在客户端使用JavaScript并不新奇。配合CSS和DHTML,适当地使用JavaScript可以为客户端增加一定的intelligence,例如在用户界面上向用户提供立即的反馈、对表单输入内容进行简单验证等,减少浏览器和服务器之间的来回。

    但是,在客户端过多使用JavaScript也有其缺陷。第一,JavaScript必须以源代码的形式下载到客户端再执行。对于某些应用,例如验证信用卡号码等,这样的运行方式有可能被恶意用户劫持,结果是不可靠的。第二,在HTML页面中嵌入大量的JavaScript来处理应用逻辑,等于把表达和应用逻辑参杂到一起,会导致软件模块间的耦合增加,降低可维护性,增加功能扩展的难度。这是软件开发中的一个大忌。

    XMLHTTPRequest为这两个问题提供了答案。XMLHTTPRequest使得JavaScript可以向服务器提出HTTP要求而不必重新加载页面。XMLHTTPRequest最早是由微软提出的。在IE上,是一个ActiveX对象。在基于Mozilla的浏览器和Apple的Safari上,XMLHTTPRequest已经内置于JavaScript解释器中了,是一个native JavaScript object。

    简单地说,首先从ActiveX或者JavaScript解释器产生一个XMLHTTPRequest对象,注册一个响应onreadystatechange事件的JavaScript事件处理函数,然后用XMLHTTPRequest的send方法向服务器的特定URL提出HTTP请求。在事件处理函数里,检查XMLHTTPRequest对象的readyState属性和status属性。如果readyState的值是“4”,并且status是“200”,那么服务器已经接受了请求,并且完成了处理。服务器送过来的HTTP应答已经存在于XMLHTTPRequest的属性中了。这里的status其实就是HTTP协议中为HTTP应答定义的状态码,“200”是OK,“404”是Page not found,等等。

    如果我们申请的URL指向一个web service,那么在XMLHTTPRequest对象的responseXML属性中就包含了DOM格式的HTTP应答。如果是普通的URL,HTTP应答则以字符串的形式存在XMLHTTPRequest对象的responseText属性中。

    拿到HTTP应答后,接下来就简单了。当然,对于达到Google Suggest那样的响应速度,还有很多其他工作。例如,Google Suggest下载到浏览器的JavaScript代码几乎就是一具“木乃伊”:没有任何不必要的的空格、空行,变量名、函数名等都是一个或两个字母。

    在上面这个极度简化的transaction中,浏览器并没有加载任何新的页面,通过XMLHTTPRequest所申请的URL甚至不会出现在浏览器的历史中。

    参考:

    http://www.adaptivepath.com/publications/essays/archives/000385.php

    http://developer.apple.com/internet/webcontent/xmlhttpreq.html

    http://www.xml.com/pub/a/2005/02/09/xml-http-request.html

    Google Suggest的地址:

    http://www.google.com/webhp?complete=1

    元宝推荐:Highway,
    • 家园 《新民晚报》应该到西西河-[信息技术]来学习一下:

      他们的网页这个问题太大了!每一页都要等半天,才看到最后那几行“真正的文字”。

      http://xmwb.news365.com.cn/

    • 家园 好东西啊。这个技术太拽了。哪天西西河有这个界面就好了。

      不过他那个在HISTORY不留痕迹也在某个角度造成了问题,就是不能BACKUP。

      什么时候试着做一个这么个类似的东西玩玩

      • 家园 哈哈,我就估摸着铁手会上钩。

        西西河的界面不用全部改成用这个东西,很多时候加载新页面还更自然一些。

        大概象用户信息、信箱一类的比较合适吧。

        期待中。。。

        • 家园 呵呵,多谢这个内容。具体做不做的了,就难说了。

          我这方面不懂,只能慢慢的琢磨。到时候有问题还是要请教的。

          不知道你有没有使用我提供的“新”显示方式?在轻轻滑过菜单里最上面的显示参数里可以选择。如果选择“新型”的话,看贴的时候,都是浮动一个窗口出来。只是我的做法比较土,是用的IFRAME。

          • 家园 奇怪,我这儿看不出区别。没有IFRAME出现。我用的

            是FireFox 1.0.1,不过也被我给customize的不象样了。套用猫论,不管“土”办法还是“洋”办法,只要能解决问题就是好办法。

            “请教”二字,可不敢当。虽然两年前干过web applications,但那是依葫芦画瓢,跟在别人后头学步而已。现在全是凭着兴趣,纸上谈兵罢了。

            倘若真要有什么河政工程需要大家出力,我挑大梁不行,但摇旗呐喊、端茶送水还是力所能及的。

            • 家园 firefox没有问题的。你要选用那个新型显示,再回到版面上

              就会发现不同了。

              河政工程方面前两天水帘洞主也和我提过一些建议,非常只好。我想,等我这段时间忙过以后,可以把我遇到的问题,有些领会在这里写写,大家一起讨论一下,看看。

    • 家园 有意思,加花!

      不过要作到跨浏览器兼容,最好还是扩展javascript,ActiveX不是正道啊.

    • 家园 减少Page Refresh确实是Web App的一个重要话题,

      以前,办法似乎有这么几种:

      1) Java Applet,比如Datek的那个实时显示Stock price的Streamer.

      点看全图

      外链图片需谨慎,可能会被源头改

      2) Microsoft Remoting Script,一直没有流行起来

      3)ActiveX component。本质上讲这已经出了Web app的范畴了,它需要在客户端安装binary code,比如现在很流行的Flash

      最近,微软又有了一种新的技术,叫做XML-HTTP Script callbacks。本质上讲,就是client side script在背后异步调用Web server上的函数,等拿到返回结果后(全部是String),再用Client side Java script更新GUI。下面就是微软的一个小例子,Page纹丝不动,但股票价格却可以“自动”更新。这个技术比较不错,但问题是很多浏览器还不支持。

      Updating Browser Displays in (Almost) Real Time

      In "An Overview of the New Services, Controls, and Features in ASP.NET 2.0" in the June 2004 issue of MSDN®Magazine, I wrote about the ASP.NET 2.0 new client callback manager and demonstrated how it can be used to transmit XML-HTTP callbacks to Web servers to convert ZIP codes into city names. Dino Esposito delved more deeply into XML-HTTP callbacks in his August 2004 Cutting Edge column ("Script Callbacks in ASP.NET").
      
      XML-HTTP callbacks enable browsers to make calls to Web servers without performing full-blown postbacks. The benefits are numerous. XML-HTTP callbacks transmit less data over the wire, thereby using bandwidth more efficiently. XML-HTTP callbacks don't cause the page to flicker because they don't cause the browser to discard the page as postbacks do. Furthermore, XML-HTTP callbacks execute less code on the server because ASP.NET short-circuits the request so that it executes the minimum amount of code necessary. Inside an XML-HTTP callback, for example, a page's Render method isn't called, significantly reducing the time required to process the request on the server.
      
      Once they learn about the ASP.NET 2.0 client callback manager, most developers can envision lots of different uses for it. But here's an application for XML-HTTP callbacks that you might not have thought of. I regularly receive e-mail from developers asking how to create two-way connections between browser clients and Web servers. The scenario generally involves an ASP.NET Web page displaying data that's continually updated on the server. The goal is to create a coupling between the browser and the Web server so that when the data changes on the server, it's automatically updated on the client, too.
      
      It sounds reasonable enough, but transmitting asynchronous notifications from a Web server to a browser is a nontrivial problem. However, XML-HTTP callbacks provide a handy solution. Rather than try to contrive a mechanism for letting a Web server send notifications to a browser, you can have the browser poll the server in the background using efficient XML-HTTP callbacks. Unlike META REFRESH tags, an XML-HTTP solution causes no flashing in the browser, producing a superior user experience. And unlike more elaborate methods that rely on maintaining open ports, an XML-HTTP-based solution, properly implemented, has minimal impact on scalability.
      
      The Web page shown in Figure 1 demonstrates how dynamic page updates using XML-HTTP callbacks work. To see for yourself, launch the page called DynamicUpdate.aspx in your browser. Then open the file named Stocks.xml in the Data directory. The fictitious stock prices displayed in DynamicUpdate.aspx come from Stocks.xml. Now change one of the stock prices in Stocks.xml and save your changes. After a brief pause (two or three seconds on average), the browser's display updates to reflect the change.

      点看全图

      外链图片需谨慎,可能会被源头改

      Figure 1 Dynamic Page Updates

      What's the magic that allowed the update to occur? XML-HTTP callbacks, of course. Figure 2 lists the source code for the codebehind class that serves DynamicUpdate.aspx. Page_Load uses the new ASP.NET 2.0 Page.GetCallbackEventReference method to obtain the name of a function it can call to initiate a callback. Then it registers its own __onCallbackCompleted function, which uses client-side script to update the client's display, to be called when a callback returns. Finally, it registers a block of startup script that uses window.setInterval to call the function that initiates callbacks―the function whose name was returned by GetCallbackEventReference. Once the page loads, it polls the server every five seconds for updated data. Any changes made to the data on the server appear in the browser after a short delay.
      
      Currently, DynamicUpdate.aspx.cs doesn't use bandwidth as efficiently as it could because every callback returns all three stock prices, even if the data hasn't changed. You could make DynamicUpdate.aspx.cs more efficient by modifying it to return only the data that has changed and to return nothing at all if no prices have changed. Then you'd have the best of both worlds: a scalable, lightweight mechanism for detecting updates on the server, and one that transmits only as much information as it must and not a single byte more. That's a win no matter how you look at it.

      using System;

      using System.Data;

      using System.Configuration;

      using System.Web;

      using System.Web.Security;

      using System.Web.UI;

      using System.Web.UI.WebControls;

      using System.Web.UI.WebControls.WebParts;

      using System.Web.UI.HtmlControls;

      public partial class DynamicUpdate_aspx

      {

      static readonly string _script1 =

      "<script language=\"javascript\">\n" +

      "function __onCallbackCompleted (result, context)\n" +

      "{{\n" +

      "var args = result.split (';');\n" +

      "var gridView = document.getElementById('{0}');\n" +

      "gridView.rows[1].cells[1].childNodes[0].nodeValue = args[0];\n" +

      "gridView.rows[2].cells[1].childNodes[0].nodeValue = args[1];\n" +

      "gridView.rows[3].cells[1].childNodes[0].nodeValue = args[2];\n" +

      "}}\n" +

      "</script>";

      static readonly string _script2 =

      "<script language=\"javascript\">\n" +

      "window.setInterval (\"{0}\", 5000);\n" +

      "</script>";

      void Page_Load(object sender, EventArgs e)

      {

      // Get a callback event reference

      string cbref = GetCallbackEventReference (this, "null",

      "__onCallbackCompleted", "null", "null");

      // Register a block of client-side script containing

      // __onCallbackCompleted

      RegisterClientScriptBlock ("MyScript", String.Format(

      _script1, GridView1.ClientID));

      // Register a block of client-side script that launches

      // XML-HTTP callbacks at five-second intervals

      RegisterStartupScript ("StartupScript", String.Format(

      _script2, cbref));

      }

      // Server-side callback event handler

      string ICallbackEventHandler.RaiseCallbackEvent(string arg)

      {

      // Read the XML file into a DataSet

      DataSet ds = new DataSet ();

      ds.ReadXml(Server.MapPath ("~/Data/Stocks.xml"));

      // Extract the stock prices from the DataSet

      string amzn = ds.Tables[0].Rows[0]["Price"].ToString ();

      string intc = ds.Tables[0].Rows[1]["Price"].ToString();

      string msft = ds.Tables[0].Rows[2]["Price"].ToString();

      // Return a string containing all three stock prices

      // (for example, "10.0;20.0;30.0")

      return (amzn + ";" + intc + ";" + msft);

      }

      }

      • 家园 给highway补充几个

        减少page refresh的办法还有。

        1)SVG (www.adobe.com)。highway所说的XML-HTTP Script callbacks的效果,SVG可以轻松做到。与XML-HTTP Script callback啥的相比,SVG更强的一点在于它已经成为W3C的标准,svg viewer在firefox和IE下面都有,浏览器的支持也没有问题。

        2)Flash 这个大家都知道了,浏览器的支持更没有问题。

        3)XAML 这个可能少见一点,属于Next Generation

        4)XUL (http://www.xulplanet.com/)

        5)CSS,在某些情况下,这玩意儿是绝招 :-)

        其实大家如果有兴趣,可以看看所谓RIA:Rich Internet Application。

        • 家园 谢谢,XAML和XUL以前没有注意到!

          Flash和其他技术不一样,它需要在client side安装plug-in,所以技术上不是什么新东西。

          • 家园 呵呵,如果你指的是做个动画啥的,flash确实不是什么新东东

            建议你看看flex(http://www.macromedia.com/software/flex/?promoid=home_prod_flex_111703),个人认为这就是GUI环境下Web application未来发展的方向。

            也许具体实现有很多种,flash,svg,js+xmlrpc,xaml,xul,java都是候选者,也都有可能成为未来的主流,但是rich internet application的概念目前实现得最成熟还是flash。

            是的,flash需要安装plugin,但是现在没有安装flash的浏览器有多少呢?不支持flash的GUI浏览器又有多少呢?可以说,有java的地方就有flash,但是有flash的地方未必有java。在普及率这么高的情况下,flash已经超过了plugin的概念了,这也是macromedia推出flex的基础。

            优秀的技术带来的不仅是视觉上的新感受,广泛的用户接受,更是概念上的提升。这一点上,flash虽然还比不上java,但是差距在不断缩小。macromedia和sun比,还是小弟弟啊。

            顺便说一下,这条河好像是用asp挖的,铁总有没有想过弄个CMS来把改造一下?

分页树展主题 · 全看


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河