[TOC]

一、背景说明

随着公司BS产品发布越来越多,开发人员比较紧张,原CS系统开发人员也主动的学习BS系统的开发,并且参与维护开发。
但CS系统和BS系统还是有一些比较大的差异的,特别是思维上要进行一些转变,否则的话,可能会出现代码看着是正确的,但运行出来的效果就有问题。或者最终效果也实现了,也知道怎么写代码,但是没有理解为什么要这样写。
所以打算把我自己的理解整理出来,跟大家一起讨论一下,让大家对这个原理理解更清楚一些。

二、界面初始展示执行步骤

下面我们假设用户已经登录系统,点击操作员维护菜单,马上进入到操作员列表界面为例进行说明

1、CS界面初始同步展示执行步骤

CS开发转BS开发时思维转换 - 图1 从上面的流程可以看出,除了查询操作员的sql语句或存储过程是在数据库服务器中执行外,我们写的所有业务代码都是直接在CS程序所在电脑中运行的。
并且这个执行过程是单线程顺序执行的,sql语句查询缓慢会直接导致操作员列表窗体的展示不出来,要等待数据最终查询完成,返回数据,并且绑定到数据窗口后才能正常展示。

2、BS界面初始同步展示执行步骤

CS开发转BS开发时思维转换 - 图2 从上面的流程可以看出,从用户点击操作员维护菜单开始,浏览器就会一直显示一个加载中的空白页面,此时请求会到达服务器(主要业务代码都是在web服务器上进行执行),服务器查询数据(sql语句在数据库服务器中执行),并且最终生成完整的html后(生成html代码也是在web服务器上执行),一起返回给浏览器,再由浏览器来呈现界面(此时浏览器只是简单的渲染,不涉及业务代码或者少量的js代码的执行)。
在整个这个过程中,用户只能等待,并且也都是串行执行的。如果数据库或者web服务器执行比较慢的话,则页面会一直呈现一个白色的空白页面,用户体验不好。
为了解决界面初始化加载时,用户等待的时候,一般会选择将同步更改为异步,详见下面的说明。

3、CS界面初始异步展示执行步骤

CS开发转BS开发时思维转换 - 图3 异步和同步的最大区别就是,用户看到界面的时间,用户可以在极短的时候内就先看到界面(生成界面的代码也是在CS系统电脑中运行),但数据仍然是显示加载中,让用户心里不会那么着急。
等数据在单独的线程中加载完成(查询数据sql或存储过程在数据库服务器中执行)后,再显示到用户界面中(线程查询数据代码,更新界面代码都是在CS系统电脑中运行),供用户查看和操作。
这种编程相对于同步来说,更复杂一些,多了线程操作,线程切换等。

4、BS界面初始异步展示执行步骤

CS开发转BS开发时思维转换 - 图4 异步和同步的最大的区别就是用户等待空白页面的时间,同步是一直等待到页面全部完成。而异步时,则是先显示页面给用户,再异步加载数据后进行显示。
从上述执行过程中可以看到:

  1. 页面的编译和执行是在web服务器中执行(Web服务器中执行)
  2. 然后执行逻辑返回到浏览器中,浏览器执行执行js脚本来异步加载数据(浏览器中执行)
  3. 此时服务器收到新的请求后又开始在web服务器中执行数据查询的代码(Web服务器中执行)
  4. 并且将sql或者存储过程发送给数据库服务器,在数据库中进行执行。(数据库中执行)
  5. 数据返回到web服务器后,进行一定的处理后(Web服务器中执行)
  6. 再进一下的返回给浏览器,此时浏览器再执行js脚本,将数据展现出来。(浏览器中执行)

    三、用户操作执行步骤

    下面以用户点击修改某个操作员为例,说明一下用户操作时的执行步骤。
    用户操作时,CS中基本都是同步操作的,所以只讲同步操作的执行步骤,异步的只是将事件的代码放到单独线程中执行,不再特别说明。
    BS中基本都是异步操作的,同步操作的话和BS界面初始展示的执行步骤相同,所以下面只讲异步操作的执行步骤。

    1、CS用户操作同步执行步骤

    CS开发转BS开发时思维转换 - 图5 从上面的执行流程中可以看出,和界面初始化的执行步骤基本相同。除查询操作员数据是在数据库中执行外,其他代码都是在CS程序所在电脑运行。

    2、BS用户操作操作异步执行步骤

    CS开发转BS开发时思维转换 - 图6 执行过程如下:

  7. 显示对话框

    1. 可以直接显示(如果结构已经加载)(浏览器中执行)
    2. 异步加载结构
      1. 服务器编译并执行页面或控制器,并且返回局部视图(Web服务器中执行)
      2. 浏览器渲染并显示页面(浏览器中执行)
  8. 异步加载操作员数据(浏览器中执行)
  9. 准备查询操作员数据(Web服务器中执行)
  10. 查询操作员数据(数据库中执行)
  11. 处理数据库返回的操作员数据并返回给浏览器(Web服务器中执行)
  12. 浏览器将数据表示在页面中,以便用户修改(浏览器中执行)

    四、如何区分BS视图中的代码是在web服务器中执行还是浏览器中执行?

    1、Razor视图

    现在基本都是使用mvc模式,razor视图就是其中的v

    1. 在web服务器中执行的代码

    1.1.以@符号开头的代码

    @ViewBag.ShortTitle
    <a href="javascript:_reloadMvcCaptchaImage()"><img src="@Url.Action("LoadCheckCode",new { r=DateTime.Now.Ticks})" alt="@GlobalResource.正在加载..." title="@GlobalResource.刷新图片" width="90" height="32" border="0"></a>
    <script type="text/javascript">
     var CommonValues = {
         TryHotelId: "@Model.TryHotelId",
         TryUserName: "@Model.TryUserName",
         TryUserPass: "@Model.TryUserPass",
         AuthLogin: "@Url.Action("AuthLogin")",
         GetBanner: "@Url.Action("GetBanner", "Account")",
         Logout: "@Url.Action("Logout")",
         LoadCheckCode: "@Url.Action("LoadCheckCode")",
         GetServicePhone: '@Url.Action("GetServicePhone", "Account")',
         GetCompanyName: '@Url.Action("GetCompanyName", "Account")',
         GetCompanyInfo:'@Url.Action("GetCompanyInfo", "Account")',
    };
    </script>
    

    1.2.包含在@{}中的代码

    @{
     Layout = null;
     var product = ViewBag.product as Gemstar.BSPMS.Common.Services.Entities.M_v_products;
     var currentNeutralUICulture = Gemstar.BSPMS.Hotel.Web.Models.CultureHelper.GetCurrentNeutralUICulture();
     var sysShortName = currentNeutralUICulture == "en" ? product?.SysShortEName : product?.SysShortName;
     ViewBag.Title = sysShortName;
    
     var domain1 = product.Domain;
     var domain2 = product.Domain2;
     string accessDomain = ViewBag.domain;
     string changeDomain = domain1;
     if (accessDomain.Contains(domain1))
     {
         changeDomain = domain2;
     }
     var protocol = ViewBag.Protocol;
    }
    
     @if (!MvcApplication.IsTestEnv)
     {
         <script type="text/javascript">var loginUrl = "@string.Format("{0}{1}", protocol, accessDomain)"; if (window.top != window) { window.top.location = loginUrl; }</script>
     }
    

    2.在浏览器中执行的代码

    除了上述特殊标记的代码外,其余代码都是原样返回到浏览器中由浏览器进行渲染和执行。
    需要执行的js代码,需要包含在