paulwong

#

XMLHttpRequest Level 2 使用指南

作者: 阮一峰

日期: 2012年9月 8日

XMLHttpRequest是一个浏览器接口,使得Javascript可以进行HTTP(S)通信。

最早,微软在IE 5引进了这个接口。因为它太有用,其他浏览器也模仿部署了,ajax操作因此得以诞生。

但是,这个接口一直没有标准化,每家浏览器的实现或多或少有点不同。HTML 5的概念形成后,W3C开始考虑标准化这个接口。2008年2月,就提出了XMLHttpRequest Level 2 草案。

这个XMLHttpRequest的新版本,提出了很多有用的新功能,将大大推动互联网革新。本文就对这个新版本进行详细介绍。

一、老版本的XMLHttpRequest对象

在介绍新版本之前,我们先回顾一下老版本的用法。

首先,新建一个XMLHttpRequest的实例。

  var xhr = new XMLHttpRequest();

然后,向远程主机发出一个HTTP请求。

  xhr.open('GET', 'example.php');

  xhr.send();

接着,就等待远程主机做出回应。这时需要监控XMLHttpRequest对象的状态变化,指定回调函数。

  xhr.onreadystatechange = function(){

    if ( xhr.readyState == 4 && xhr.status == 200 ) {

      alert( xhr.responseText );

    } else {

      alert( xhr.statusText );

    }

  };

上面的代码包含了老版本XMLHttpRequest对象的主要属性:

  * xhr.readyState:XMLHttpRequest对象的状态,等于4表示数据已经接收完毕。

  * xhr.status:服务器返回的状态码,等于200表示一切正常。

  * xhr.responseText:服务器返回的文本数据

  * xhr.responseXML:服务器返回的XML格式的数据

  * xhr.statusText:服务器返回的状态文本。

二、老版本的缺点

老版本的XMLHttpRequest对象有以下几个缺点:

  * 只支持文本数据的传送,无法用来读取和上传二进制文件。

  * 传送和接收数据时,没有进度信息,只能提示有没有完成。

  * 受到"同域限制"(Same Origin Policy),只能向同一域名的服务器请求数据。

三、新版本的功能

新版本的XMLHttpRequest对象,针对老版本的缺点,做出了大幅改进。

  * 可以设置HTTP请求的时限。

  * 可以使用FormData对象管理表单数据。

  * 可以上传文件。

  * 可以请求不同域名下的数据(跨域请求)。

  * 可以获取服务器端的二进制数据。

  * 可以获得数据传输的进度信息。

下面,我就一一介绍这些新功能。

四、HTTP请求的时限

有时,ajax操作很耗时,而且无法预知要花多少时间。如果网速很慢,用户可能要等很久。

新版本的XMLHttpRequest对象,增加了timeout属性,可以设置HTTP请求的时限。

  xhr.timeout = 3000;

上面的语句,将最长等待时间设为3000毫秒。过了这个时限,就自动停止HTTP请求。与之配套的还有一个timeout事件,用来指定回调函数。

  xhr.ontimeout = function(event){

    alert('请求超时!');

  }

目前,Opera、Firefox和IE 10支持该属性,IE 8和IE 9的这个属性属于XDomainRequest对象,而Chrome和Safari还不支持。

五、FormData对象

ajax操作往往用来传递表单数据。为了方便表单处理,HTML 5新增了一个FormData对象,可以模拟表单。

首先,新建一个FormData对象。

  var formData = new FormData();

然后,为它添加表单项。

  formData.append('username', '张三');

  formData.append('id', 123456);

最后,直接传送这个FormData对象。这与提交网页表单的效果,完全一样。

  xhr.send(formData);

FormData对象也可以用来获取网页表单的值。

  var form = document.getElementById('myform');

  var formData = new FormData(form);

  formData.append('secret', '123456'); // 添加一个表单项

  xhr.open('POST', form.action);

  xhr.send(formData);

六、上传文件

新版XMLHttpRequest对象,不仅可以发送文本信息,还可以上传文件。

假定files是一个"选择文件"的表单元素(input[type="file"]),我们将它装入FormData对象。

  var formData = new FormData();

  for (var i = 0; i < files.length;i++) {

    formData.append('files[]', files[i]);

  }

然后,发送这个FormData对象。

  xhr.send(formData);

七、跨域资源共享(CORS)

新版本的XMLHttpRequest对象,可以向不同域名的服务器发出HTTP请求。这叫做"跨域资源共享"(Cross-origin resource sharing,简称CORS)。

使用"跨域资源共享"的前提,是浏览器必须支持这个功能,而且服务器端必须同意这种"跨域"。如果能够满足上面的条件,则代码的写法与不跨域的请求完全一样。

  xhr.open('GET', 'http://other.server/and/path/to/script');

目前,除了IE 8和IE 9,主流浏览器都支持CORS,IE 10也将支持这个功能。服务器端的设置,请参考《Server-Side Access Control》

八、接收二进制数据(方法A:改写MIMEType)

老版本的XMLHttpRequest对象,只能从服务器取回文本数据(否则它的名字就不用XML起首了),新版则可以取回二进制数据。

这里又分成两种做法。较老的做法是改写数据的MIMEType,将服务器返回的二进制数据伪装成文本数据,并且告诉浏览器这是用户自定义的字符集。

  xhr.overrideMimeType("text/plain; charset=x-user-defined");

然后,用responseText属性接收服务器返回的二进制数据。

  var binStr = xhr.responseText;

由于这时,浏览器把它当做文本数据,所以还必须再一个个字节地还原成二进制数据。

  for (var i = 0, len = binStr.length; i < len; ++i) {

    var c = binStr.charCodeAt(i);

    var byte = c & 0xff;

  }

最后一行的位运算"c & 0xff",表示在每个字符的两个字节之中,只保留后一个字节,将前一个字节扔掉。原因是浏览器解读字符的时候,会把字符自动解读成Unicode的0xF700-0xF7ff区段。

八、接收二进制数据(方法B:responseType属性)

从服务器取回二进制数据,较新的方法是使用新增的responseType属性。如果服务器返回文本数据,这个属性的值是"TEXT",这是默认值。较新的浏览器还支持其他值,也就是说,可以接收其他格式的数据。

你可以把responseType设为blob,表示服务器传回的是二进制对象。

  var xhr = new XMLHttpRequest();

  xhr.open('GET', '/path/to/image.png');

  xhr.responseType = 'blob';

接收数据的时候,用浏览器自带的Blob对象即可。

  var blob = new Blob([xhr.response], {type: 'image/png'});

注意,是读取xhr.response,而不是xhr.responseText。

你还可以将responseType设为arraybuffer,把二进制数据装在一个数组里。

  var xhr = new XMLHttpRequest();

  xhr.open('GET', '/path/to/image.png');

  xhr.responseType = "arraybuffer";

接收数据的时候,需要遍历这个数组。

  var arrayBuffer = xhr.response;

  if (arrayBuffer) {

    var byteArray = new Uint8Array(arrayBuffer);

    for (var i = 0; i < byteArray.byteLength; i++) {

      // do something

    }
  }

更详细的讨论,请看Sending and Receiving Binary Data

九、进度信息

新版本的XMLHttpRequest对象,传送数据的时候,有一个progress事件,用来返回进度信息。

它分成上传和下载两种情况。下载的progress事件属于XMLHttpRequest对象,上传的progress事件属于XMLHttpRequest.upload对象。

我们先定义progress事件的回调函数。

  xhr.onprogress = updateProgress;

  xhr.upload.onprogress = updateProgress;

然后,在回调函数里面,使用这个事件的一些属性。

  function updateProgress(event) {

    if (event.lengthComputable) {

      var percentComplete = event.loaded / event.total;

    }

  }

上面的代码中,event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable不为真,则event.total等于0。

与progress事件相关的,还有其他五个事件,可以分别指定回调函数:

  * load事件:传输成功完成。

  * abort事件:传输被用户取消。

  * error事件:传输中出现错误。

  * loadstart事件:传输开始。

  * loadEnd事件:传输结束,但是不知道成功还是失败。

十、阅读材料

  1. Introduction to XMLHttpRequest Level 2: 新功能的综合介绍。

  2. New Tricks in XMLHttpRequest 2:一些用法的介绍。

  3. Using XMLHttpRequest:一些高级用法,主要针对Firefox浏览器。

  4. HTTP Access Control:CORS综述。

  5. DOM access control using cross-origin resource sharing:CORS的9种HTTP头信息

  6. Server-Side Access Control:服务器端CORS设置。

  7. Enable CORS:服务端CORS设置。

(完)

posted @ 2015-08-07 12:24 paulwong 阅读(490) | 评论 (0)编辑 收藏

理解DOMString、Document、FormData、Blob、File、ArrayBuffer数据类型

     摘要: 一、XMLHttpRequest 2.0的家臣们我大学那会儿,一个称为Ajax的东西对前端行业造成了深远影响,不仅是JS语言,而包括前端地位、职位兴起以及工作分工等。抛开IE6浏览器不谈,其他浏览器的Ajax实际上都是借助XMLHttpRequest实现的。然后,好多年过去了,XMLHttpRequest带着两位家臣,DOMString和Document数据类型攻城略地,几乎一统天下。然时代是发展...  阅读全文

posted @ 2015-08-07 12:08 paulwong 阅读(820) | 评论 (0)编辑 收藏

AJAX下载+监控进度+保存文件

全程用AJAX下载文件,并显示下载进度,之后保存文件。

HTML5文件:

<!DOCTYPE html>
<html>
<head>
    <title>XMLHttpRequest Download Progress</title>
</head>
<body>
    <progress id="p"></progress>
    <input type="button" onclick="downloadAndSave();" value="Download"/>
    <script>
        
function downloadAndSave()
        {
            
var progressBar = document.getElementById('p'), xhr = new XMLHttpRequest();
            xhr.open('GET', '
2');
            xhr.responseType 
= "arraybuffer";
            xhr.onprogress 
= function(event) {
                
if(event.lengthComputable) {
                    progressBar.max 
= event.total;
                    progressBar.value 
= event.loaded;
                }
            };
            xhr.onloadend 
= function(event) {
                progressBar.value 
= event.loaded;
                saveByeToFile('
2', xhr.response);
            };
            xhr.send();
        }
        
        
function saveByeToFile(name, arrayBuffer) {
            
var byteArray = new Uint8Array(arrayBuffer);
            
var a = window.document.createElement('a');

            a.href 
= window.URL.createObjectURL(new Blob([ byteArray ], {
                type : 'application
/octet-stream'
            }));
            a.download 
= name;

            
// Append anchor to body.
            document.body.appendChild(a)
            a.click();

            
// Remove anchor from body
            document.body.removeChild(a)
        }
    
</script>
</body>
<html>

posted @ 2015-08-06 19:17 paulwong 阅读(1143) | 评论 (0)编辑 收藏

SONY PS4的用户登录机制

  1. 如果你买了PS4,要玩数字版的游戏,就必须要新建一个帐号,绑定信用卡,购买游戏,下载游戏,玩耍。

  2. 如果你有多于一台的PS4,则可用之前的帐号登录,下载已购买的游戏,玩耍,但又要在第三台PS4上登录,则不被允许。

  3. 如果刚刚那台PS4上有多于一个帐号,则可授权给其他用户玩已购买的游戏,只需做“登录为常用的PS4”即可,但这个授权只能授权一台。

  4. 一个帐号,同一时间只能在二台PS4上玩游戏。且这两台PS4只能一台用别人的帐号玩自己购买的游戏,另一台只能用自己的帐号玩自己的游戏。

  5. 如果在网页上解绑了帐号与PS4的关系,那这个帐号又可以在另一个PS4上登录,并授权给别的用户下载、玩自己的游戏,但这种网页解绑只能半年做一次。原先的已经绑定的PS4上的别的用户只要不去用你的帐号登录,则SONY不会检查此帐号的授权有效性,即你可以继续玩。

  6. 这样就变成有一个假授权PS4、一个真授权PS4和一个只能用自己帐号的的PS4。

PS4游戏怎么买省钱?小编讲解合购游戏
http://www.pcpop.com/doc/1/1011/1011606.shtml

某宝上信誉好的店买PS4合购游戏到底安全吗?
http://www.zhihu.com/question/23386383

posted @ 2015-07-20 21:07 paulwong 阅读(1023) | 评论 (0)编辑 收藏

员工激励

员工激励机制

俗话说 “水不激不扬,人不激不奋” 是我国古代典型的激励思想。中国古代在激励方面有颇多论述和实践,我认为中国儒家思想博大精深,但不太好操作。

什么是激励?

激励过程可以看作是外部刺激、个体内部条件、行为表现和行为结果的共同作用过程。 激励是一个动态变化循环的过程:奖励目标→努力→绩效→奖励→满意→努力,这其中还有个人完成目标的能力,获得奖励的期望值,觉察到的公平,消耗力量、能力等一系列因素。只有综合考虑到各个方面,才能取得满意的激励效果。

为什么要激励?

我们将“付出”,“回报”放在一架天枰上:

  • 当天枰两侧相等时,员工感到公平;
  • 当天枰左侧大于(〉)右侧时,员工感到占了便宜,行为有: ——员工产生歉疚感,从而更努力工作。 ——员工心安理得。

  • 当天枰左侧小于(〈)右侧时,员工感到吃了亏,行为有: ——员工争取更多的奖酬、待遇。 ——员工减少自己投入努力,如迟到早退、怠工、出废品、浪费原料、放弃责任。 ——员工想方设法把参照者的奖酬待遇拉下来。 ——员工想要参照者工作干得更多。 ——参照者心理上调节对这些变量的认识(类似于用阿Q精神),使之平衡。 ——改变参照对象,求得“比上不足、比下有余”的自慰效果。 ——在企业没法达到公平感觉时,员工辞职,另谋高就。

公平感觉纯粹是主观、心理上的反应。在现实中,人们常常高估自己的投入贡献,低估别人的投入贡献,从而造成观察问题的系统偏差。

何时激励员工

员工激励是无时无刻的,伴随整个职业生涯,而非需要的时候激励一把。

在哪激励员工

同样员工激励可以是任何时间任何地点。

谁来激励员工

很多企业认为激励员工是人力资源的工作,人力资源部门职能确实包此项工作,但人力资源部门实施起来也有很多不足的地方。 首先人力资源部门并不熟悉每个部门的工作细节,如果各部门或小组能够内部激励员工效果远远好于由人力资源部门主导的相关工作。

激励的误区

画饼方法,很多企业采用这种方法,这种激励在当下已经失去了作用或收效甚微。先不说画饼是否能兑现,画饼法设置的目标太遥远,而到达目标途中每步细节是缺失的。

最常见的例子就是大会上老板说“大家好好干,达到业绩,年底发奖金”,会议结束老板回到自己的办公室,员工回到自己的位置上该干什么干什么。 因为公司的业绩就像股市一样不可预测,这个年终奖就像买彩票或是场赌博,且风险很大,员工都默认放弃,顺其自然,能拿到奖金也好,拿不到也没有什么付出。

当员工得到奖励,可能热情状态能保持几天,几周,一两个月,这种热情状态不可能持续保持,在这个期间员工的工作状态是有显著提升的。高潮过去随后热情就会消退,慢慢回到正常的工作状态。 所以激励是持续的,渐进的,激励密度也很有讲究,“密”与“”都会影响激励的效果。

怎样激励员工

从上面的天枰法则我们可以看到,激励就是不停地调整法码。有哪些激励方法呢:

  1. 表率激励
  2. 荣誉激励
  3. 奖惩激励
  4. 目标激励
  5. 物质激励
  6. 情感激励
  7. 公平激励
  8. 信任激励
  9. 赏识激励
  10. 尊重激励
  11. 参与激励
  12. 荣誉激励
  13. 关心激励
  14. 相互激励
  15. 股票增值
  16. 股票期權
  17. 虛擬股票
  18. 員工持股

激励方式太多了,无法依依列举,你可以参考相关管理学的书籍,近代管理学有很成熟激励方法,以及很多成熟的案例参考。

我想谈的是“激励图”,这是我多年总结出来的图表。供大家参考。 激励图

从激励图中我们可以看到:

  1. 从不激励的企业,员工永远是常态工作,偶尔还会产生负面情绪。
  2. 如果激励与下一次激励间隔过长效果就不明显
  3. 当激励后间隔太长或者停止激励,员工在经过一段常态的工作后,会出现负能量增长的情况
  4. 最不好的结果是一旦激励完后直接进入消极阶段
  5. 正能量常态的团队,这种团队最常见的就是直销,保险行业,激励后的结果我们无法预知,已经上升到精神层面。
  6. 让激励成为常态,持续不断激励这是每个企业需要思考的一个问题。
http://my.oschina.net/neochen/blog/479169

posted @ 2015-07-20 10:02 paulwong 阅读(443) | 评论 (0)编辑 收藏

LMAX资源

Disruptor 是一个 Java 的并发编程框架,大大的简化了并发程序开发的难度,在性能上也比 Java 本身提供的一些并发包要好。



老家
https://github.com/LMAX-Exchange/disruptor/wiki/Getting-Started


并发编程网:
http://ifeve.com/?x=0&y=0&s=disruptor

Disruptor使用入门
http://blog.csdn.net/workformywork/article/details/38359447

java Disruptor工作原理,谁能用一个比喻形容下?
http://www.zhihu.com/question/23235063

致敬disruptor:CAS实现高效(伪)无锁阻塞队列实践
http://www.majin163.com/2014/03/24/cas_queue/


并发框架Disruptor译文
http://coolshell.cn/articles/9169.html#more-9169

通过Axon和Disruptor处理1M tps
http://ifeve.com/axon/

示范代码
http://code.taobao.org/svn/simple-project/

posted @ 2015-07-13 18:49 paulwong 阅读(332) | 评论 (0)编辑 收藏

100万并发连接服务器笔记之Java Netty处理1M连接会怎么样

     摘要: 前言每一种该语言在某些极限情况下的表现一般都不太一样,那么我常用的Java语言,在达到100万个并发连接情况下,会怎么样呢,有些好奇,更有些期盼。这次使用经常使用的顺手的netty NIO框架(netty-3.6.5.Final),封装的很好,接口很全面,就像它现在的域名 netty.io,专注于网络IO。整个过程没有什么技术含量,浅显分析过就更显得有些枯燥无聊,准备好,硬着头...  阅读全文

posted @ 2015-07-13 18:26 paulwong 阅读(4351) | 评论 (0)编辑 收藏

高并发情况下怎样尽量实现无锁编程

  一个在线2k的游戏,每秒钟并发都吓死人。传统的hibernate直接插库基本上是不可行的。我就一步步推导出一个无锁的数据库操作。

  

  1. 并发中如何无锁。

  一个很简单的思路,把并发转化成为单线程。Java的Disruptor就是一个很好的例子。如果用java的concurrentCollection类去做,原理就是启动一个线程,跑一个Queue,并发的时候,任务压入Queue,线程轮训读取这个Queue,然后一个个顺序执行。

  在这个设计模式下,任何并发都会变成了单线程操作,而且速度非常快。现在的node.js, 或者比较普通的ARPG服务端都是这个设计,“大循环”架构。

  这样,我们原来的系统就有了2个环境:并发环境 + ”大循环“环境

  并发环境就是我们传统的有锁环境,性能低下。

  ”大循环“环境是我们使用Disruptor开辟出来的单线程无锁环境,性能强大。

  

  2. ”大循环“环境 中如何提升处理性能。

  一旦并发转成单线程,那么其中一个线程一旦出现性能问题,必然整个处理都会放慢。所以在单线程中的任何操作绝对不能涉及到IO处理。那数据库操作怎么办?

  增加缓存。这个思路很简单,直接从内存读取,必然会快。至于写、更新操作,采用类似的思路,把操作提交给一个Queue,然后单独跑一个Thread去一个个获取插库。这样保证了“大循环”中不涉及到IO操作。

  

  问题再次出现:

  如果我们的游戏只有个大循环还容易解决,因为里面提供了完美的同步无锁。

  但是实际上的游戏环境是并发和“大循环”并存的,即上文的2种环境。那么无论我们怎么设计,必然会发现在缓存这块上要出现锁。

  

  3. 并发与“大循环”如何共处,消除锁?

  我们知道如果在“大循环”中要避免锁操作,那么就用“异步”,把操作交给线程处理。结合这2个特点,我稍微改下数据库架构。

  原本的缓存层,必然会存在着锁,例如:

public TableCache
{
  private HashMap<String, Object> caches = new ConcurrentHashMap<String, Object>();
}

  这个结构是必然的了,保证了在并发的环境下能够准确的操作缓存。但是”大循环“却不能直接操作这个缓存进行修改,所以必须启动一个线程去更新缓存,例如:

  private static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();

  EXECUTOR.execute(new LatencyProcessor(logs));

  class LatencyProcessor implements Runnable
  {
      public void run()
     {
       // 这里可以任意的去修改内存数据。采用了异步。
    }
  }

  OK,看起来很漂亮。但是又有个问题出现了。在高速存取的过程中,非常有可能缓存还没有被更新,就被其他请求再次获取,得到了旧的数据。

  

  4. 如何保证并发环境下缓存数据的唯一正确?

  我们知道,如果只有读操作,没有写操作,那么这个行为是不需要加锁的。

  我使用这个技巧,在缓存的上层,再加一层缓存,成为”一级缓存“,原来的就自然成为”二级缓存“。有点像CPU了对不?

  一级缓存只能被”大循环“修改,但是可以被并发、”大循环“同时获取,所以是不需要锁的。

  当发生数据库变动,分2种情况:

  1)并发环境下的数据库变动,我们是允许有锁的存在,所以直接操作二级缓存,没有问题。

  2)”大循环“环境下数据库变动,首先我们把变动数据存储在一级缓存,然后交给异步修正二级缓存,修正后删除一级缓存。

  这样,无论在哪个环境下读取数据,首先判断一级缓存,没有再判断二级缓存。

  这个架构就保证了内存数据的绝对准确。

  而且重要的是:我们有了一个高效的无锁空间,去实现我们任意的业务逻辑。

  

  最后,还有一些小技巧提升性能。

  1. 既然我们的数据库操作已经被异步处理,那么某个时间,需要插库的数据可能很多,通过对表、主键、操作类型的排序,我们可以删除一些无效操作。例如:

  a)同一个表同一个主键的多次UPdate,取最后一次。

  b)同一个表同一个主键,只要出现Delete,前面所有操作无效。

  2. 既然我们要对操作排序,必然会存在一个根据时间排序,如何保证无锁呢?使用

     private final static AtomicLong _seq = new AtomicLong(0);

  即可保证无锁又全局唯一自增,作为时间序列。

posted @ 2015-07-13 18:20 paulwong 阅读(779) | 评论 (0)编辑 收藏

推荐系统资源

http://www.ibm.com/developerworks/cn/opensource/os-recommender2/index.html?ca=drs-

posted @ 2015-07-07 16:39 paulwong 阅读(367) | 评论 (0)编辑 收藏

mongodb运维之副本集实践

     摘要: 正式环境,4台机器+一台定时任务的机器。 服务器是阿里云的ECS, 负载均衡用的是阿里云的SLB, mysql用阿里云的RDS, 缓存用阿里云的OCS, 运维基本上是都不需要担心了, 现在的云服务已经非常完善了, 其实我们用阿里云的服务非常多, 大概有20多个类型的服务, 感谢阿里云。 而我的技术栈是nodejs + mongodb,而阿里云有k-v兼容redis协议的nosql,无mongodb...  阅读全文

posted @ 2015-06-30 10:30 paulwong 阅读(1894) | 评论 (0)编辑 收藏

仅列出标题
共115页: First 上一页 35 36 37 38 39 40 41 42 43 下一页 Last