当前位置: 首页 > news >正文

JavaScript And Ajax(JavaScript 基本示例)

       这里通过一个示例,演示使用 js 为费时的页面改善用户体验。

 

创建 JavaScript 页面处理器

       多少次单击网页后,只看到 IE 的那个小球不停的转动,好像永不停息?是你的因特网连接速度下降了吗?和后端系统的连接有错误了吗?系统比较慢?这些问题通常会使新的基于 Web 的解决方案变得复杂。

       遇到这种情况,应向用户提供进度信息,让他们知道系统正在处理他们的请求,以便帮助用户重建对程序的信心,改善用户体验。

       提供状态信息的一个常用方法是使用 js 创建一个标准的页面处理器。用户从一个页面导航到另一个需要长时间处理的页面时,页面处理器立刻出现并显示一个标准信息(可能是滚动的文本)。同时,被请求的页面在后台下载。一旦结果页面可用,页面处理器消息就被请求的页面取代。

       把 js 代码加到目标页面不能解决处理延时的问题。因为在页面处理结束和呈现的 HTML 返回给用户前这些代码不会被处理!但是,你可以创建一个通用的页面处理器,由它处理网站中所有耗时的页面的请求。

       创建这样一个页面处理器,需要响应 onload 和 onunload 事件。下面的 PagePrecessor.aspx 页面示范了这种模式,它显示了一个表格,添加了一些文本及事件:

<body onload="BeginPageLoad();" onunload="EndPageLoad();">
    <form id="frmPageLoader" runat="server" method="post">
    <div>
        <table width="99%" border="0">
            <tr>
                <td align="center" valign="middle">
                    <span id="MessageText">Loading Page - Please Wait</span> 
                    <span id="ProgressMeter"></span>
                </td>
            </tr>
        </table>
    </div>
    </form>
</body>

 

       需要请求该页面处理器,并把实际要访问的页面作为查询字符串参数传入,例如,如果要加载 TimeConsumingPage.aspx,应该使用这个 URL:

PagePrecessor.aspx?Page=TimeConsumingPage.aspx

 

       这个页面处理器只需要很少的服务器端代码。其实,它所要做的只是从查询字符串中获得原始请求的页面并把它保存到一个受保护页面类变量里这点非常有用!因为以后你就可以使用 ASP.NET 数据绑定表达式使该变量对 js 代码公开,稍后就会看到)。

       这是 PagePrecessor.aspx 页面的服务器端代码:

public partial class PageProcessor : System.Web.UI.Page
{
    protected string PageToLoad;
 
    protected void Page_Load(object sender, EventArgs e)
    {
        this.PageToLoad = Request.QueryString["Page"];
    }
}

 

       剩余的工作由客户端的 js 完成。当页面处理器第一次加载时,onload 事件被触发,它调用客户端的 BeginPageLoad() 函数。这个函数将保持当前窗口打开并开始获取用户请求的页面。需要使用到 window.setInterval() 方法它设置一个定时器定期调用自定义的 UpdateProgressMeter() 函数)。

       这是 js 函数 BeginPageLoad() 的代码:

<script type="text/javascript">
    var iLoopCounter = 1;
    var iMaxLoop = 6;
    var iIntervalId;
 
    function BeginPageLoad() {
        // Redirect the browser to another page while keeping focus
        location.href = "<%=PageToLoad %>";
 
        // Update progress meter every 1/2 second.
        iIntervalId = window.setInterval
            ("iLoopCounter=UpdateProgressMeter(iLoopCounter,iMaxLoop)", 500);
    }
</script>

       第一行代码把页面指向新 URL 。需要注意到的是,你想要下载的页面并没有硬编码到 js 代码中。相反,它由数据绑定表达式动态设置,页面在服务器上呈现时,ASP.NET 自动插入 PageToLoad 变量的值。

 

       UpdateProgressMeter() 方法定期修改状态信息,使之看起来更像是动态的进度表:

function UpdateProgressMeter(iCurrentLoopCounter, iMaximumLoops) {
    var progressMeter = document.getElementById("ProgressMeter");
    iCurrentLoopCounter += 1;
    if (iCurrentLoopCounter <= iMaximumLoops) {
        progressMeter.innerHTML += ".";
        return iCurrentLoopCounter;
    } else {
        progressMeter.innerHTML = "";
        return 1;
    }
}

 

       最后,当页面完全加载后,客户端 onunload 事件被触发,调用 EndPageLoad() 函数停止计时器,清空进度信息并设置新页面在浏览器呈现后立刻消失的临时变化信息:

function EndPageLoad() {
    window.clearInterval(iIntervalId);
    var progressMeter = document.getElementById("ProgressMeter");
    progressMeter.innerHTML = "Page loaded - Now Transferring";
}

 

       整个过程中没有回传。最终结果是一个进度信息,它在目标页面被完全处理和加载后消失!

       为了测试这个页面处理器,可添加一个页面来进行测试:

protected void Page_Load(object sender, EventArgs e)
{
    System.Threading.Thread.Sleep(5000);
}

 

       现在可以尝试请求页面处理器并转向到这个页面:

image

       只要一小段客户端 js 代码,就可以让用户知道页面正在处理。因为用户知情,他感觉性能和体验也上升了。

 

使用 JavaScript 异步下载图片

       先前的示例演示了如何创建更具响应性的界面,这种便利性不仅仅在于页面处理器,还可以使用 js 在后台下载页面较耗时的部分,虽然需要做更多工作,但它可以提供更好的用户体验

       加入,要在 GridView 里显示记录列表,其中一个字段显示小图像。它需要一个专门的页面获取图像,根据你的设计,它可能要为每条记录分别访问文件系统或数据库。多数情况下,你可以优化这一设计(例如,在绑定网格前把图片预先加载到缓存),但是如果图片来自第三方就不可行了。

 

       下面这个示例正是这种情况。它显示一些书并从 Amazon 网站获取相关的图片。

       记录数很大的时候,显示完整列表需要花不少时间。可以使用立刻出现的占位图像解决这一问题,真正的图像在后台获取并在获得后立刻显示。这样的做法显示含有全部图片的列表的总时间不会变化,但用户能够在图片下载前就开始阅读和滚动数据,图片加载速度的缓慢易于被用户接受。

       这个例子先创建显示 GridView 的页面,代码使用一个 XML 文件的静态列表填充 DataSet 并绑定网格:

protected void Page_Load(object sender, EventArgs e)
{
    DataSet ds = new DataSet();
    ds.ReadXml(Server.MapPath("Books.xml"));
    GridView1.DataSource = ds.Tables["Book"];
    GridView1.DataBind();
}

       XML 文件的内容:

<?xml version="1.0" encoding="utf-8" ?>
<Books>
  <Book Title="Expert C# Business Objects" isbn="1590593448" Publisher="Apress"></Book>
  <Book Title="C# and the .NET Platform" isbn="1590590554" Publisher="Apress"></Book>
  <Book Title="Beginning XSLT" isbn="1590592603" Publisher="Apress"></Book>
  <Book Title="SQL Server Security Distilled" isbn="1590592190" Publisher="Apress"></Book>
</Books>

       XML 数据并不包括任何图片信息。这些细节需要从 Amazon 网站获取。GridView 直接绑定到可用的列(Title、isbn、Publisher),然后通过另一个页面根据 ISBN 获取相应的图像

 

       这是不包含样式信息的 GridView 控件标签:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
    <Columns>
        <asp:BoundField DataField="Title" HeaderText="Title" />
        <asp:BoundField DataField="isbn" HeaderText="ISBN" />
        <asp:BoundField DataField="Publisher" HeaderText="Publisher" />
        <asp:TemplateField>
            <HeaderTemplate>
                Book Cover
            </HeaderTemplate>
            <ItemTemplate>
                <img src="UnknowBook.gif" onerror="this.src='UnknowBook.gif';" 
                onload="GetBookImage(this,'<%# DataBinder.Eval(Container.DataItem,"isbn") %>');" />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

       创新的是最后一列,它包含一个 <img> 标签。这个标签没有直接指向 GetBookImage.aspx,src 特性被设置为一个本地图像文件,它可以被快速下载显示。然后,onload 事件在缺省图像第一次显示后立刻发生,开始在后台下载真正的图像并在完成后开始替换。为了确保在发生错误时,不至于显示一个红色 X ,代码处理了 onerror 事件

 

       onload 事件调用 js 函数,传入当前图像控件的引用以及图书的 ISBN,ISBN 通过数据绑定表达式得到。js 函数调用另一个页面为图书获得图片,它把 ISBN 作为查询字符串参数指定自己希望获得的图片:

function GetBookImage(img, url) {
    // Detach the event handler(the code makes just 
    // one attempt to get the picture)
    img.onload = null;
 
    // Try to get the picture from the GetBookImage.aspx page.
    img.src = 'GetBookImage.aspx?isbn=' + url;
}

 

       GetBookImage.aspx 页面执行获取所需图像的耗时任务,这可能涉及访问 Web 服务或连接数据库。这里,GetBookImage.aspx 页面直接把处理工作交给一个叫做 FindBook 的专门类,一旦得到 URL,它重定向页面

protected void Page_Load(object sender, EventArgs e)
{
    FindBook findBook = new FindBook();
    string imageUrl = findBook.GetImageUrl(Request.QueryString["isbn"]);
    Response.Redirect(imageUrl);
}

 

       FindBook 类复杂一些。它抓取屏幕查找 <img> 标签以获得 Amazon 网站上的图片。遗憾的是,Amazon 的图像缩略图没有明确的命名规则,不能够直接检索 URL。但是,根据 ISBN 可以找到图书的详细页面,可以遍历图书详细页面的 HTML 以找到图像的 URL:

public class FindBook
{
    public string GetWebPageAsString(string url)
    {
        WebRequest requestHtml = WebRequest.Create(url);
        WebResponse responseHtml = requestHtml.GetResponse();
        StreamReader r = new StreamReader(responseHtml.GetResponseStream());
        string htmlContent = r.ReadToEnd();
        r.Close();
        return htmlContent;
    }
 
    // Amazon 的图像 URL 大多使用如下的格式
    // http://ec1.images-amazon.com/I/[ImageName].jpg
 
    public string GetImageUrl(string isbn)
    {
        try
        {
            isbn = isbn.Replace("-", "");
            string bookUrl = "http://www.amazon.com/exec/obidos/ASIN/" + isbn;
 
            string bookHtml = GetWebPageAsString(bookUrl);
            string imgTagPattern = "<img src=\"(http://ecx.images-amazon.com/images/I/[^\"]+)\"";
            Match imgTagMatch = Regex.Match(bookHtml, imgTagPattern);
            return imgTagMatch.Groups[1].Value;
        }
        catch
        {
            return "";
        }
    }
}

       现在运行程序,默认图片会首先出现,接着程序会后台获取真正的图片,拿到正确的地址后会逐一替换默认图片

 

       不过,类似这样的处理,使用专门的 Amazon Web 服务显然是更灵活且更健壮的做法。但是它不会改变这个例子,这个例子演示了使用 js 对性能的提升。

相关文章:

  • linux centos 如何设置swap大小?
  • 【资源共享】RK3288 WiFiBT 开发配置参考说明
  • 仪表运算放大器INA333
  • 5分钟快速了解es6常用特性
  • Hadoop 2.0 NameNode HA和Federation实践
  • 再也不用担心this指向的问题了
  • 快速理解URL重写
  • 12月,1000人,来一场属于敏捷人的重逢吧!
  • 话里话外:成功CEO的用人之道——按需激励
  • 001-ant design pro 页面加载原理及过程,@connect 装饰器
  • 对ASP网站程序的设计
  • “一盘货卖全球”之后,天猫今年将推出国货“出海2.0版”
  • 分析图第一讲前期准备,渲染白模5.9
  • java如何获取SQL查询结果集中的行数和列数
  • 中小型企业到底需要什么样的ERP
  • 分享的文章《人生如棋》
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • Github访问慢解决办法
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • java8 Stream Pipelines 浅析
  • PHP 小技巧
  • Spring思维导图,让Spring不再难懂(mvc篇)
  • 从0到1:PostCSS 插件开发最佳实践
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 前嗅ForeSpider教程:创建模板
  • 入门级的git使用指北
  • 算法之不定期更新(一)(2018-04-12)
  • 小程序开发中的那些坑
  • 7行Python代码的人脸识别
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • 整理一些计算机基础知识!
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • ​马来语翻译中文去哪比较好?
  • (003)SlickEdit Unity的补全
  • (1) caustics\
  • (day 2)JavaScript学习笔记(基础之变量、常量和注释)
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (ISPRS,2023)深度语义-视觉对齐用于zero-shot遥感图像场景分类
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (初研) Sentence-embedding fine-tune notebook
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (强烈推荐)移动端音视频从零到上手(下)
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (五)c52学习之旅-静态数码管
  • (一)python发送HTTP 请求的两种方式(get和post )
  • (转)可以带来幸福的一本书
  • (转)原始图像数据和PDF中的图像数据
  • .NET CF命令行调试器MDbg入门(四) Attaching to Processes
  • .NET Conf 2023 回顾 – 庆祝社区、创新和 .NET 8 的发布
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .Net中wcf服务生成及调用
  • /boot 内存空间不够
  • @ 代码随想录算法训练营第8周(C语言)|Day57(动态规划)
  • @angular/cli项目构建--Dynamic.Form