西红柿爱番茄

Feed Rss

礼拜一点小想法,写了个半成品,只供试玩,有心思再来优化解析方式,让它支持更多的语法。
试用地址:http://www.ilovejs.net/lab/makeHTML.html

按需加载,顾名思义就是在用户需要这个功能的时候就初始化这个功能,加载相关的脚本和样式文件等等。普通我们使用的方式,就是在需要的时候,就添加一个文件的url进行加载,并且用一个对象来记录已经加载过的文件。这种方式有些散乱,对于是随意加载的,那倒是不可避免,但是对于一个项目来说,页面的的功能和相应的文件是确定的,那么还是使用上面的方式的话,那么在后期的维护上会比较混乱,增加了成本。

对项目之外的文件加载,使用普通的方式散乱在代码中,也不太合适,那么就需要一个封装的加载器,统一加载文件的接口和调用方式。我下面将要讲的“加载器”,不是传说中的模块化中的加在方式,我更多的是从代码维护方面来考虑,使得一目了然的看到页面本身的功能需要按需加载一些什么文件列表,并且可以标记已经加载的文件,而不会使得url散乱在页面中。

//需要按需加载的内部文件列表映射
mis.classFiles = {
  'AjaxEvent': 'includes/ajax.lib.js',
  'AjaxRequest': 'includes/request.lib.js',
  'colorFade': 'includes/effects.lib.js'
}

//标记已经include的内部文件
mis.includedFiles = {};

//对内的文件加载
mis.include = function(classname,callback){
  if(mis.includedFiles[classname]){
    callback && callback();
	  return true;
  }else if(mis.classFiles[classname]){
	  return mis.loadJavaScript(mis.classFiles[classname],callback);
  }else{
	  return false;
  }
}

//标记已经load的内部和外部文件
mis.loadedJavaScript = {}

//无限制的加载file文件
mis.loadJavaScript = function(file,callback){
  callback = callback || function(){};
  if(mis.loadedJavaScript[file]){
	  callback(true);
	  return true;
  }else{
	  var head = document.getElementsByTagName("head")[0];
	  var script = head.appendChild(document.createElement("script"));

    script.onload = script.onreadystatechange = function(){
		  if((!/*@cc_on!@*/0) || (/loaded|complete/).test(script.readyState)){
        script.onreadystatechange = null;
	      mis.loadedJavaScript[file] = true;
	      callback(true);
		  }
	  }

	  script.src = file;
	  return true;
  }
}

代码上没啥技巧,只是让它看起来更直观了点而已。

在我所负责的产品项目中,在代码编码模式上,使用了函数式编程的方案。约定唯一的命名空间,提供namespace、mixin等基本的语言扩展功能。或者这并没有什么,重要的是一套编码模式。在linux中来说,就是将一个任务细化为一个细小、单一的功能。在我的方案中,基于目前公司开发流程上的约定和线上代码的发布方式,使用一个唯一的命名空间,之后通过这命名空间来维护代码的组织,将一个功能细化,尽量细化到功能单一,保持每一个函数都能够在20行代码以内,并且提供语义化清晰的命名,以及结构化的注释方式,这样代码看起来就整齐有道,极富特点,看起来愉悦,其中一个主要的是提高复用度和较少重复代码和重复功能。

在维护阶段,因为由于维护人员的不同,以前的做法是使用闭包的方式,来包含每一个人新增的代码,保持代码不影响其他的功能。这种方式是可取的,但是这样不容易形成统一的编码方式,在大方式上抓不住,特别在codereview的时候,不能形成统一的阅读方式;而且,使用闭包的方式,在代码复用度等方面基本是难以把握的,基本是代码堆砌,无视之前的实现代码中是否有能够复用的功能函数。使用函数式的方式,那么在维护方面,可以很方便的在原来的代码中复用功能,或者添加、删除功能,因为都在同一个context上下文中,同在一个命名空间下。

使用了函数式编程的方式之后,在我最近的一次项目中,得到了很好的实践,在频繁的需求更改中,由于将功能细化,实际上就是一个大功能,由一堆小功能函数根据不用的条件组织而成。那么在修改功能的时候,只是需要修改其中的小功能函数,或者是删除、增加某个小功能函数,都显得很方便,也很快速,在功能切换上也能够很快的过度。

尽量保持一个函数在20行以内,会让维护者看代码的时候很兴奋。

鉴于目前规划部署项目的静态文件管理和制定页面开发规范,整理出了一个符合项目特点的HTML5规范页面,使用了更有语义化的HTML5标签。趁热打铁,遂将本博客也更新到了HTML5,使得博客的信息内容架构使用更有语义化的标签来展示。比如下图就是博客首页的HTML DOM结构图:

了解更多

  1. 条件表达式通常有两种表现形式,第一种:所有分支都是属于正常行为;第二种:条件表达式提供的答案只有一种是正常行为。其他都是不常见的情况。如果两条分支都是正常行为,就应该使用if~else的条件表达式;如果某个条件极其罕见,就应该单独检查该条件,并在该条件为真时立刻从函数中返回。

    function getPayAmount(){
      var result;
      if(isDead) result = deadAmount();
      else{
        if(isSeparated) result = separatedAmount();
    	else{
    	  if(isRetired) result = retiredAmount();
    	  else result = normalPayAmount();
    	}
      }
      return result;
    }
    

    可以转化为:

    function getPayAmount(){
      if(isDead) return deadAmount();
      if(isSeparated) return separatedAmount();
      if(isRedired) return retiredAmount();
      return normalAmount();
    }
    
  2. 在条件表达式的每个分支上有着相同的一段执行代码,这段代码跟分支的逻辑无关的时候,将这段重复代码搬移到条件表达式之外。

    if(isSpecialDeal()){
      total = price * 0.95;
      send();
    }else{
      total = price * 0.98;
      send();
    }
    

    可以转化为:

    if(isSpecialDeal()){
      total = price * 0.95;
    }else{
      total = price * 0.98;
    }
    send();
    
  3. 如果分支条件过于复杂,那么可以将分支条件提炼出来作为一个独立函数,并提供一个语义化更好的名称用于分支判断中。使用它的优势是使得在分支中的代码可读性更好,以至于我不需要知道具体的分支判断条件,就可以理解代码的意图。

    if(date.before(SUMMER_START) || date.after(SUMMER_END)){
      charge = quantity * _winterRate * _winterServiceCharge;
    }else{
      charge = quantity * _summerRate;
    }
    

    可以转化为:

    if(notSummer(date)){
      charge = winterCharge(quantity);
    }else{
      charge = summerCharge(quantity);
    }
    
    function notSummer(date){
      return date.before(SUMMER_START) || date.after(SUMMER_END);
    }
    function summerCharge(quantity){
      return quantity * _summerRate;
    }
    function winterCharge(quantity){
      return quantity * _winterRate * _winterServiceCharge;
    }
    
  4. 合并条件表达式。如果有一系列的条件判断,都得到相同的结果;或者嵌套的条件判断。那么将这些条件合并为一个条件表达式,可能的话将这个合并的表达式提炼为一个独立的函数。

    function disabilityAmount(){
      if(_seniority < 2) return 0;
      if(_monthsDisabled) return 0;
      if(_isPartTime) return 0;
      return 1;
    }
    

    可以转化为:

    function disabilityAmount(){
      if(_seniority < 2 || _monthsDisabled || _isPartTime) return 0;
      return 1;
    }
    

    还可以转化为:

    function disabilityAmount(){
      if(isNotEligibleForDisability()) return 0;
      return 1;
    }
    
    function isNotEligibleForDisability(){
      return _seniority < 2 || _monthsDisabled || _isPartTime;
    }
    
  5. 将条件逻辑反转。有时候使用条件反转的方式,可以很大程度上简化if判断逻辑,特别是在嵌套if判断的时候。

    function getAdjustedCapital(){
      var result = 0;
      if(_capital > 0){
        if(_intRate > 0 && _duration > 0){
          result = (_income / _duration) * ADJ_FACTOR;
    	}
      }
      return result;
    }
    

    可以转化为:

    function getAdjustedCapital(){
      if(_capital <= 0) return 0;
      if(_intRate <= 0 || _duration <=0) return 0;
      return (_income / _duration) * ADJ_FACTOR;
    }
    

    再简化为:

    function getAdjustedCapital(){
      if(_capital <= 0 || _intRate <= 0 || _duration <=0) return 0;
      return (_income / _duration) * ADJ_FACTOR;
    }
    

charset的作用:告诉浏览器,对于服务器端返回来的HTML文件流用何种编码进行解码,从而进行HTML的解析操作。

有三个地方可以设置charset,而且它们的优先级是有顺序的:1、response header;2、HTML文档中的meta;3、浏览器默认的charset声明。那么它们的优先级是如何的呢?

首先要了解浏览器处理charset的策略:浏览器首先会在服务器返回的response header头中检查是否有charset声明,如果没有,就接着检查HTML head部分的meta标签,是否有声明charset,如果还没有,那么就使用浏览器默认的charset方式进行解码文档流。

在response header头中声明好了charset,那么浏览器在第一时间接收到HTML数据包的时候,就会以这个charset编码进行解码HTML文件流,这种情况下是最快的方式;如果response header头中没找到,那么浏览器会delay解析HTML文档,检查1KB以内的HTML内容是否会包含有charset声明的meta标签。如果还找不到,那么就使用浏览器默认的charset声明进行解码HTML页面,但是这时,已经delay了一些时间了。

如果处理的适当,那么这个delay时间是完全可以避免的,使得HTML页面可以尽可能快的让浏览器使用显示声明的编码进行解码文件流。那就是:在服务端设置好请求内容的charset编码;始终在页面中meta标签内声明charset,当然了,content-type也是十分有必要的。