• <高性能JavaScript>笔记 [7~10]


    七:Ajax
    其实这个章节主要分为了2个部分,数据传输数据格式
    主要描述如何通过客户端语言来实现数据的交互。

    常用五种向服务器请求数据的技术:
    • XMLHttpRequest(XHR)//也就是所谓的Ajax
    • Dynamic script tag insertion//动态脚本注入
    • iframes
    • Comet
    • Multipart XH
    在现代高性能JavaScript中使用的三种技术是:XHR,动态脚本注入和Multipart XHR。

    关于XHR就不多介绍了,主要就是通过XMLHttpRequest对象来实现服务器数据的发送和接受。
    详细的学习跳去:http://www.w3school.com.cn/ajax/index.asp
    不过值得注意的是,主流浏览器可以通过监听readyState值等于3,你可以与正在传输中的服务器响应进行交互。当readyState值等于3,说明此时正在和服务器交互,响应信息还在传输过程中,这就是所谓的“流”(streaming),可以有效提高数据请求的性能。
    低版本的IE不仅不支持“流”,也没有提供readyState为3的状态,而且XHR不支持外域请求数据。
    使用XHR时,用GET请求可以缓存数据,不过URL的长度超过2048个字符时,要考虑使用POST请求,因为IE限制了URL的长度。

    动态脚本注入最强大的地方,就是可以实现跨域请求数据,不过这也很容易导致安全性问题。

    Multipart XHR是一种新的技术,允许客户端之用一个HTTP请求就可以从服务器端传送多个资源。通过服务器端把css、html、js和图片打包成一个双方约定的字符串分割的长字符串并发送到客户端。
    下面是一个简单的例子,通过把多张图片转换成base64编码的字符串,只需一次http请求就可以获取:
    //JavaScript
    var req = new XMLHttpRequest();
    req.open("GET", "hosts.php", true);
    req.onreadystatechange = function() {
    	if(req.readyState == 4) {
    		splitImages(req.responseText);
    	}
    };
    req.send(null);
    
    
    function splitImages(imagesString) {
    	var imageData = imagesString.split("\u0001");
    	var imageElement;
    	
    	for(var i = 0, len = imageData.length; i<len; i++) {
    		imageElement = document.createElement("img");
    		imageElement.src = "data:image/jpeg;base64," + imageData[i];
    		document.getElementById("container").appendChild(imageElement);
    	}
    }
    

      

    //PHP
    //读取图片并将他们转换为base64编码的字符串
    $images = array("1.jpg", "2.jpg", "3.jpg");
    foreach($images as $image) {
    	$image_fh = fopen($image, "r");
    	$image_data = fread($image_fh, filesize($image));
    	fclose($image_fh);
    	$playloads[] = base64_encode($image_data);
    }
    //把字符串合并成为一个长字符串,然后输出它
    $newline = chr(1); //该字符串不会出现在任何base64字符串中
    echo implode($newline, $playloads);
    

      

    如果MXHR响应信息的体积越来越大,有必要通过监听readyState为3的状态来实现“流”操作。
    编写健壮的MXHR代码很复杂,相关类库地址:http://techfoolery.com/mxhr/
    这个技术最大的缺点就是所获得的资源不能被浏览器缓存,因为合并后的资源是作为字符串传输的。
    老板IE不支持readyState为3的状态和data:URL


    发送数据的部分,两种广泛使用的技术就是:XHR和Beacons(信标)
    这里简单谈谈Beacons,这项技术非常类似动态脚本注入。通过创建一个新的Image对象,并把src属性设置为服务器上脚本的URL。该URL包含了我们要通过GET传回的键值对数据。
    var url = "/status_tracker.php";
    var params = [
    	"step=2",
    	"time=1248027314"
    ];
    (new Image()).src = url + "?" + params.join("&");
    
    注意,不需要创建img元素或把它插入DOM。
    Beacons很简单,但无法发送POST请求,另外,需要通过监听Image对象的load事件,才能判断服务器是否成功接收数据。

    数据格式
    当考虑数据传输技术时,你必须考虑这些因素:功能集、兼容性、性能以及方向(发送给服务器还是从服务器接收)。而当考虑数据格式时,唯一需要比较的就是速度。

    XML:
    当Ajax最先开始流行时,它选择了XML作为数据格式,因为当时它有很多优势:极佳的通用性、格式严格、易于验证。
    不过相比其他格式,XML很冗长,每一个单独的数据片段都需要依赖大量的结构,实际有效的数据比例非常低。而且解析XML要提前知道其详细结构,还必须确切地知道如何解析这个结构并费力地将它重组到JavaScript对象中。
    也可以把没一个值都转换成为标签的属性,这样可以压缩xml文件的大小,也不需要遍历复杂的DOM,大大提高的速度。
    但就算这样,和JSON相比还是慢太多了。

    JSON:
    JSON是一种是用JavaScript对象和数组直接量编写的轻量级且易于解析的数据格式。
    通过XHR请求json文件时,数据以字符串形式发送到客户端,这个时候大多数人习惯用eval()来把json字符串解析为json对象。
    但这样存在安全性和性能上的问题。
    最好的方法就是使用JSON.parse()方法解析,此方法已被 IE8(S)/Firefox3.5+/Chrome4/Safari4/Opera10 原生支持,对于旧版浏览器可以使用非原生版本来处理:http://json.org/json2.js

    JSONP:
    关于JSONP的介绍,书上实在含糊不清,详细了解可以到这里:http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html

    自定义格式:
    自定义格式在对于非常大的数据集请求时,是最快的格式。

    Ajax性能指南
    • 减少请求数,可通过合并JavaScript和CSS文件,或使用MXHR。
    • 缩短页面的加载时间,页面主要内容加载完成后,用Ajax获取那些次要的文件。
    • 确保你的代码错误不会输出给用户,并在服务器端处理错误。
    • 知道何时使用成熟的Ajax类库,以及何时编写自己的底层Ajax代码。




    八:编程实践

    1.通过避免使用eval()和Function()构造器来避免双重求值带来的性能消耗。同样的,给setTimeout()和setInterval()传递函数而不是字符串作为参数。
    当你在JavaScript代码中执行另一段JavaScript代码时,都会导致双重求值的性能消耗。此代码首先会以正常的方式求值,然后在执行过程中对包含于字符串中的代码发起另一个求职运算。

    2.尽量使用直接量创建对象和数组。直接量的创建和初始化都比非直接量形式要快。
    var myArray = new Array();
    myArray[0] = "Nicholas";
    myArray[1] = 50;
    myArray[2] = true;
    myArray[3] = null;
    
    var myArray = ["Nicholas", 50, true, null]; //直接量创建速度更快

    3.避免做重复的工作。当需要检测浏览器时,可使用延迟加载条件预加载
    function addHandler(target, eventType, handler){
    	if (target.addEventListener){ //DOM2 Events
    		target.addEventListener(eventType, handler, false);
    	} else { //IE
    		target.attachEvent("on" + eventType, handler);
    	}
    }
    
    function removeHandler(target, eventType, handler){
    	if (target.removeEventListener){ //DOM2 Events
    		target.removeEventListener(eventType, handler, false);
    	} else { //IE
    		target.detachEvent("on" + eventType, handler);
    	}
    }

    每一次都进行了同样的检查,查看指定方法是否存在。如果你假定target唯一的值就是DOM对象,而且用户不可能在页面加载完成后神奇地改变浏览器,那么这种判断就是重复的。
    如果每一次调用addHandler()时就确定addEventListener()是存在的,那么随后每次调用时它应该也都存在。

    延迟加载:
    function addHandler(target, eventType, handler){
    	//overwrite the existing function
    	if (target.addEventListener){ //DOM2 Events
    		addHandler = function(target, eventType, handler){
    			target.addEventListener(eventType, handler, false);
    		};
    	} else { //IE
    		addHandler = function(target, eventType, handler){
    			target.attachEvent("on" + eventType, handler);
    		};
    	}
    	//call the new function
    	addHandler(target, eventType, handler);
    }
    
    function removeHandler(target, eventType, handler){
    	//overwrite the existing function
    	if (target.removeEventListener){ //DOM2 Events
    		removeHandler = function(target, eventType, handler){
    			target.addEventListener(eventType, handler, false);
    		};
    	} else { //IE
    		removeHandler = function(target, eventType, handler){
    			target.detachEvent("on" + eventType, handler);
    		};
    	}
    	//call the new function
    	removeHandler(target, eventType, handler);
    }

    条件预加载:
    var addHandler = document.body.addEventListener ?
    	function(target, eventType, handler){
    	    target.addEventListener(eventType, handler, false);
    	}:
    	function(target, eventType, handler){
    	    target.attachEvent("on" + eventType, handler);
    	};
    	
    var removeHandler = document.body.removeEventListener ?
    	function(target, eventType, handler){
    	    target.removeEventListener(eventType, handler, false);
    	}:
    	function(target, eventType, handler){
    	    target.detachEvent("on" + eventType, handler);
    	};
    

      


    4.在进行数学计算时,考虑使用直接操作数字的二进制形式的位运算

    对2的取模运算,一般用于实现表格行颜色交替:
    for (var i=0, len=rows.length; i < len; i++){
    	if (i % 2) {
    		className = "even";
    	} else {
    		className = "odd";
    	}
    	//apply class
    }
    

    但下面按位与版本比上面的版本快乐50%(取决于浏览器)

    for (var i=0, len=rows.length; i < len; i++){
    	if (i & 1) {
    		className = "odd";
    	} else {
    		className = "even";
    	}
    	//apply class
    }

    5.JavaScript的原生方法总比你写的任何代码都要快。尽量使用原生方法





    九:构建并部署高性能JavaScript应用
    • 合并JavaScript文件以减少HTTP请求数。
    • 使用YUI Compressor压缩JavaScript文件。
    • 在服务器端压缩JavaScript文件(Gzip编码)。
    • 通过正确设置HTTP响应头来缓存JavaScript文件,通过向文件名增加时间戳来避免缓存问题。
    • 使用CDN(Content Delivery Network)提供JavaScript文件;CDN不仅可以提升性能,它也为你管理文件的压缩与缓存。




    十:工具
    这章主要就是介绍了各种各样的工具来优化页面的性能和加载,这里就不一一介绍了。
    其中自然少不了浏览器的开发人员工具,如果了解浏览器Console的API,可以阅读我这篇文章:http://www.cnblogs.com/maplejan/archive/2012/10/20/2732021.html




  • 相关阅读:
    JavaScript WebSocket C# SuperSocket.WebSocket 示例
    Nginx 配置
    Temporary Post Used For Theme Detection (272f6d70fb8946f3a568afd3d7b053bd 3bfe001a32de4114a6b44005b770f6d7)
    SpringBoot多数据源事务解决方案
    SpringBoot集成mybatis拦截器修改表名
    点击各个按钮,在执行操作之前出现确认提示框
    incoming change和current change
    Expected Number with value 8, got String with value "8".
    正则只能输入数字遇到的问题
    Antd 4.19 Modal + Form;打开modal时使用setFieldsValue,首次回显正常,第二次无效?
  • 原文地址:https://www.cnblogs.com/maplejan/p/2732015.html
Copyright © 2020-2023  润新知