JavaScript实现与web通信的方法详解

web通信,一个特别大的topic,涉及面也是很广的。因最近学习了 javascript 中一些 web 通信知识,在这里总结下。文中应该会有理解错误或者表述不清晰的地方,还望斧正!

一、前言

1. comet技术

浏览器作为 Web 应用的前台,自身的处理功能比较有限。浏览器的发展需要客户端升级软件,同时由于客户端浏览器软件的多样性,在某种意义上,也影响了浏览器新技术的推广。在 Web 应用中,浏览器的主要工作是发送请求、解析服务器返回的信息以不同的风格显示。AJAX 是浏览器技术发展的成果,通过在浏览器端发送异步请求,提高了单用户操作的响应性。但 Web 本质上是一个多用户的系统,对任何用户来说,可以认为服务器是另外一个用户。现有 AJAX 技术的发展并不能解决在一个多用户的 Web 应用中,将更新的信息实时传送给客户端,从而用户可能在“过时”的信息下进行操作。而 AJAX 的应用又使后台数据更新更加频繁成为可能。

随着互联网的发展,web 应用层出不穷,也不乏各种网站监控、即时报价、即时通讯系统,为了让用户得到更好的体验,服务器需要频繁的向客户端推送信息。开发者一般会采用基于 AJAX 的长轮询方式或者基于 iframe 及 htmlfile 的流方式处理。当然有些程序需要在客户端安装各种插件( Java applet 或者 Flash )来支持性能比较良好的“推”信息。

2. HTTP协议中的长、短连接

短连接的操作步骤是:建立连接——数据传输——关闭连接...建立连接——数据传输——关闭连接
长连接的操作步骤是:建立连接——数据传输...(保持连接)...数据传输——关闭连接

长连接与短连接的不同主要在于client和server采取的关闭策略不同。短连接在建立连接以后只进行一次数据传输就关闭连接,而长连接在建立连接以后会进行多次数据数据传输直至关闭连接(长连接中关闭连接通过Connection:closed头部字段)。

二、web 通信

首先要搞清楚,xhr 的 readystate 各种状态。

属性 描述
onreadystatechange 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
readyState 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。

0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 请求处理中
4: 请求已完成,且响应已就绪

status 200: "OK"
404: 未找到页面

1.轮询

轮询是一种“拉”取信息的工作模式。设置一个定时器,定时询问服务器是否有信息,每次建立连接传输数据之后,链接会关闭。

前端实现:

var polling = function(url, type, data){
  var xhr = new XMLHttpRequest(),
    type = type || "GET",
    data = data || null;

  xhr.onreadystatechange = function(){
    if(xhr.readyState == 4) {
      receive(xhr.responseText);
      xhr.onreadystatechange = null;
    }
  };

  xhr.open(type, url, true);
  //IE的ActiveXObject("Microsoft.XMLHTTP")支持GET方法发送数据,
  //其它浏览器不支持,已测试验证
  xhr.send(type == "GET" ? null : data);
};

var timer = setInterval(function(){
  polling();
}, 1000);

在轮询的过程中,如果因为网络原因,导致上一个 xhr 对象还没传输完毕,定时器已经开始了下一个询问,上一次的传输是否还会在队列中,这个问题我没去研究。如果感兴趣可以自己写一个ajax的请求管理队列。

2.长轮询(long-polling)

长轮询其实也没啥特殊的地方,就是在xhr对象关闭连接的时候马上又给他接上~ 看码:

var longPoll = function(type, url){
  var xhr = new XMLHttpRequest();

  xhr.onreadystatechange = function(){
    // 状态为 4,数据传输完毕,重新连接
    if(xhr.readyState == 4) {
      receive(xhr.responseText);
      xhr.onreadystatechange = null;

      longPoll(type, url);
    }
  };

  xhr.open(type, url, true);
  xhr.send();
}

只要服务器断开连接,客户端马上连接,不让他有一刻的休息时间,这就是长轮询。

3.数据流

数据流方式,在建立的连接断开之前,也就是 readystate 状态为 3 的时候接受数据,但是麻烦的事情也在这里,因为数据正在传输,你拿到的 xhr.response 可能就是半截数据,所以呢,最好定义一个数据传输的协议,比如前2个字节表示字符串的长度,然后你只获取这个长度的内容,接着改变游标的位置。

假如数据格式为: data splitChar data为数据内容,splitChar为数据结束标志(长度为1)。 那么传输的数据内容为 data splitChar data splitChar data splitChar...

var dataStream = function(type, url){
  var xhr = new XMLHttpRequest();

  xhr.onreadystatechange = function(){

    // 状态为 3,数据接收中
    if(xhr.readyState == 3) {
      var i, l, s;

      s = xhr.response; //读取数据
      l = s.length;   //获取数据长度

      //从游标位置开始获取数据,并用分割数据
      s = s.slice(p, l - 1).split(splitChar);

      //循环并操作数据
      for(i in s) if(s[i]) deal(s[i]);

      p = l; //更新游标位置

    }

    // 状态为 4,数据传输完毕,重新连接
    if(xhr.readyState == 4) {
      xhr.onreadystatechange = null;

      dataStream(type, url);
    }
  };

  xhr.open(type, url, true);
  xhr.send();
};

这个代码写的是存在问题的,当readystate为3的时候可以获取数据,但是这时获取的数据可能只是整体数据的一部分,那后半截就拿不到了。readystate在数据传输完毕之前是不会改变的,也就是说他并不会继续接受剩下的数据。我们可以定时去监听readystate,这个下面的例子中可以看到。

这样的处理不算复杂,但是存在问题。上面的轮询和长轮询是所有浏览器都支持的,所以我就没有写兼容IE的代码,但是这里,低版本IE不允许在readystate为3的时候读取数据,所以我们必须采用其他的方式来实现。

在ajax还没有进入web专题之前,我们已经拥有了一个法宝,那就是iframe,利用iframe照样可以异步获取数据,对于低版本IE可以使用iframe来接受数据流。

if(isIE){
  var dataStream = function(url){
    var ifr = document.createElement("iframe"), doc, timer;

    ifr.src = url;
    document.body.appendChild(ifr);

    doc = ifr.contentWindow.document;

    timer = setInterval(function(){

      if(ifr.readyState == "interactive"){
        // 处理数据,同上
      }

      // 重新建立链接
      if(ifr.readyState == "complete"){
        clearInterval(timer);

        dataStream(url);
      }
    }, 16);
  };
};

定时去监听iframe的readystate的变化,从而获取数据流,不过,上面的处理方式还是存在问题。数据流实现“服务器推”数据的原理是什么呢,简单点说,就是文档(数据)还没有加载完,这个时候浏览器的工作就是去服务器拿数据完成文档(数据)加载,我们就是利用这点,给浏览器塞点东西过去~ 所以上述利用iframe的方式获取数据,会使浏览器一直处于加载状态,title上的那个圈圈一直在转动,鼠标的状态也是loading,这看着是相当不爽的。幸好,IE提供了HTMLFile对象,这个对象就相当于一个内存中的Document对象,它会解析文档。所以我们创建一个HTMLFile对象,在里面放置一个IFRAME来连接服务器。这样,各种浏览器就都支持了。

if(isIE){
  var dataStream = function(url){
    var doc = new ActiveXObject("HTMLFile"),
      ifr = doc.createElement("iframe"),
      timer, d;

    doc.write("<body/>");

    ifr.src = url;
    doc.body.appendChild(ifr);

    d = ifr.contentWindow.document;

    timer = setInterval(function(){

      if(d.readyState == "interactive"){
        // 处理数据,同上
      }

      // 重新建立链接
      if(d.readyState == "complete"){
        clearInterval(timer);

        dataStream(url);
      }
    }, 16);
  };
};

4.websocket

websocket是前端一个神器,ajax用了这么久了,相关技术也是很成熟,不过要实现个数据的拉取确实十分不易,从上面的代码中也看到了,各种兼容性问题,各种细节处理问题,自从有了websocket,哈哈,一口气上五楼...

var ws = new WebSocket("ws://www.example.com:8888");

ws.onopen = function(evt){};
ws.onmessage = function(evt){
  deal(evt.data);
};
ws.onclose = function(evt){};

//ws.close();

新建一个WebSocket实例,一切就OK了,ws:// 是websocket的连接协议,8888为端口号码。onmessage中提供了data这个属性,相当方便

5.EventSource

HTML5中提供的EventSource这玩意儿,这是无比简洁的服务器推送信息的接受函数。

new EventSource("test.php").onmessage=function(evt){
  console.log(evt.data);
};

简洁程度和websocket是一样的啦,只是这里有一个需要注意的地方,test.php输出的数据流应该是特殊的MIME类型,要求是"text/event-stream",如果不设置的话,你试试~ (直接抛出异常)

6.ActionScript

情非得已就别考虑这第六种方式了,虽说兼容性最好,要是不懂as,出了点bug你也不会调试。

具体实现方法:在 HTML 页面中内嵌入一个使用了 XMLSocket 类的 Flash 程序。JavaScript 通过调用此 Flash 程序提供的套接口接口与服务器端的套接口进行通信。JavaScript 在收到服务器端以 XML 格式传送的信息后可以很容易地控制 HTML 页面的内容显示。

7.Java Applet套接口

这玩意儿原理和Flash类似,不过我不懂,就不细说了。

三、后端处理方式

本文主要是总结Javascript的各种通讯方式,后端配合node来处理,应该是挺给力的。

var conns = new Array();

var ws = require("websocket-server");
var server = ws.createServer();

server.addListener("connection", function(connection){
 console.log("Connection request on Websocket-Server");
 conns.push(connection);
 connection.addListener('message',function(msg){
    console.log(msg);
    for(var i=0; i<conns.length; i++){
      if(conns[i]!=connection){
        conns[i].send(msg);
      }
    }
  });
});
server.listen(8888);

下面是一个php的测试demo。

header('Content-Type:text/html; charset=utf-8');
while(1){
  echo date('Y-m-d H:i:s');
  flush();
  sleep(1);
};

四、web 通信方式利弊分析

  • 轮询,这种方式应该是最没技术含量的,操作起来最方便,不过是及时性不强,把定时器的间隔时间设置的短一些可以稍微得到缓和。
  • 长轮询,算是比较不错的一个web通讯方式,不过每次断开连接,比较耗服务器资源,客户端到无所谓。
  • 数据流,他和长轮询不同之处是接受数据的时间不一样,数据流是readystate为3的时候接受,低版本IE不太兼容,处理起来略麻烦,而且还要自己设计数据传输协议。不过他对资源的消耗比上面几种都可观。
  • websocket和EventSource,两个利器,不过,没几个浏览器支持,这是比较让人伤心~
  • ActionScript和Java Applet,两者都是需要在客户端安装插件的,一个是Flash插件,一个是Java插件,而且搞前端的人一般对这东西不太熟悉,如果没有封装比较好的库可以使用,那建议还是别用了。

五、参考资料

http://www.ibm.com/developerworks/cn/web/wa-lo-comet/Comet:基于 HTTP 长连接的“服务器推”技术

http://blog.csdn.net/yankai0219/article/details/8208776  HTTP协议中长连接、短连接

http://www.web-tinker.com/  comet系列文章

到此这篇关于JavaScript实现与web通信的方法详解的文章就介绍到这了,更多相关JavaScript与web通信内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • javascript与webservice的通信实现代码

    在我这里,我选择将xml直接转换为json,以便后续javascript应用的处理.我使用.net平台构建简单的webservice. Request.asmx 复制代码 代码如下: using System; using System.IO; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Web; using System.Web.Ser

  • 在vue中使用SockJS实现webSocket通信的过程

    最近接到一个业务需求,需要做一个聊天信息的实时展示的界面,这就需要和服务器端建立webSocket连接,从而实现数据的实时获取和视图的实时刷新.在此将我的实现记录下来,希望可以给有同样需求的人一些帮助.废话少说,下面我就来讲一下我的实现过程: socksjs •客户端和服务器端api尽可能简洁,尽量靠近websocket api •支持服务端扩展和负载均衡技术 •传输层应该全面支持跨域通信 •如果受到代理服务器的限制,传输层能优雅地从一种方式回退到另一种方式 •尽可能快地建立连接 •客户端只是纯

  • Python通过websocket与js客户端通信示例分析

    具体的 websocket 介绍可见 http://zh.wikipedia.org/wiki/WebSocket 这里,介绍如何使用 Python 与前端 js 进行通信. websocket 使用 HTTP 协议完成握手之后,不通过 HTTP 直接进行 websocket 通信. 于是,使用 websocket 大致两个步骤:使用 HTTP 握手,通信. js 处理 websocket 要使用 ws 模块: Python 处理则使用 socket 模块建立 TCP 连接即可,比一般的 soc

  • 基于Node.js的WebSocket通信实现

    node的依赖包 node中实现Websocket的依赖包有很多,websocket.ws均可,本文选取ws来实现,首先安装依赖 npm install ws 聊天室实例 假如A,B,C,D用户均通过客户端连接到Websocket服务,其中每个人发的消息都需要将其通过Websocket转发给其他人,此场景类似于服务端将A的消息广播给组内其他用户. 服务端实现 首先来看服务端程序,具体的工作流程分以下几步: 创建一个WebSocketServer的服务,同时监听8080端口的连接请求. 每当有新的

  • Flutter使用JsBridge方式处理Webview与H5通信的方法

    目前,移动跨平台开发作为移动开发的重要组成部分,是移动开发者必须掌握的技能,也是自我提升的重要手段.作为Google推出的跨平台技术方案,Flutter具有诸多的优势,已经或正在被广大开发者应用在移动应用开发中.在过去的2019年,我看到越来越多的公司和个人开始使用Flutter来开发跨平台应用,对于移动应用开发来说,Flutter能够满足几乎所有的业务开发需求,所以,学习Flutter正当时. 众所周知,使用Flutter进行项目开发时,就免不了要加载H5页面,在移动开发中打开H5页面需要使用

  • JavaScript/jQuery、HTML、CSS 构建 Web IM 远程及时聊天通信程序

    以及需要用到Http方式和Openfire通信的第三方库(JabberHTTPBind). JabberHTTPBind是jabber提供的XMPP协议通信的Http bind发送的形式,它可以完成WebBrowser和Openfire建立长连接通信. 主要通信流程如下图所示: 用户A通过JavaScript jsjac.js库发送一条消息到JabberHTTPBind这个Servlet容器,然后JabberHTTPBind的Servlet容器会向Openfire发送XMPP协议的XML报文.O

  • WebSocket+node.js创建即时通信的Web聊天服务器

    本文实例node.js创建即时通信的Web聊天服务器,供大家参考,具体内容如下 1.使用nodejs-websocket  nodejs-websocket是基于node.js编写的一个后端实现websocket协议的库,  连接:https://github.com/sitegui/nodejs-websocket.  (1)安装  在项目目录下通过npm安装:npm install nodejs-websocket  (2)创建服务器 //引入nodejs-websocket var ws

  • nodejs结合socket.io实现websocket通信功能的方法

    本文实例讲述了nodejs结合socket.io实现websocket通信功能的方法.分享给大家供大家参考,具体如下: 因为项目中有需要实时获取后台数据的场景,之前一直是使用http心跳请求的方法.因为websocket与此模式相比有很大的性能提升,而且可以提高实时性,所以对websocket作了一些研究.这里是使用nodejs+socket.io来实现的. 达成目标 将原来心跳请求后台数据的方式,修改为通过socket连接后台统一推送的方式.后台的数据由别的进程写入文件或写入redis,这里实

  • 详解python3实现的web端json通信协议

    之前有用python3实现过tcp协议的,后来又实现了http协议的通信,今天公司想做一个功能自动测试系统, 下午弄了一会,发现json格式的实现可以更简单一点,代码如下:简单解说一下,一般与服务器通信分两块,一块是get协议,一块是post协议, get协议很简单,直接就可访问了,post协议,实际上把data数据用起来,程序直接会自动辨别类型. 在写的过程中遇到3个问题: 1 在实现post协议时曾遇到错误, 大致说数据格式的问题,解决方法很简单,转为utf-8格式:bytes(data,

  • JavaScript实现与web通信的方法详解

    web通信,一个特别大的topic,涉及面也是很广的.因最近学习了 javascript 中一些 web 通信知识,在这里总结下.文中应该会有理解错误或者表述不清晰的地方,还望斧正! 一.前言 1. comet技术 浏览器作为 Web 应用的前台,自身的处理功能比较有限.浏览器的发展需要客户端升级软件,同时由于客户端浏览器软件的多样性,在某种意义上,也影响了浏览器新技术的推广.在 Web 应用中,浏览器的主要工作是发送请求.解析服务器返回的信息以不同的风格显示.AJAX 是浏览器技术发展的成果,

  • JavaScript 中有关数组对象的方法(详解)

    JS 处理数组多种方法 js 中的数据类型分为两大类:原始类型和对象类型. 原始类型包括:数值.字符串.布尔值.null.undefined 对象类型包括:对象即是属性的集合,当然这里又两个特殊的对象----函数(js中的一等对象).数组(键值的有序集合). 数组元素的添加 arrayObj.push([item1 [item2 [. . . [itemN ]]]]); 将一个或多个新元素添加到数组结尾,并返回数组新长度 arrayObj.unshift([item1 [item2 [. . .

  • Javascript中的迭代、归并方法详解

    迭代方法 在Javascript中迭代方法个人觉得尤为重要,在很多时候都会有实际上的需求,javascript提供了5个迭代方法来供我们操作,它们分别为: every() 对数组中的每一个项运用给定的函数,如果每项都返回true,那么就会返回true filter() 对数组中的每一个项运用给定的函数,把返回true的项组成一个新数组并返回 forEach() 对数组中的每一项运用给定的函数,但是没有任何的返回值 map() 对数组中的每一个项运用给定的函数并返回每次函数调用的结果组成新的数组

  • JavaScript中Number对象的toFixed() 方法详解

    定义和用法 toFixed() 方法可把 Number 四舍五入为指定小数位数的数字. 语法 NumberObject.toFixed(num) 参数 描述 num 必需.规定小数的位数,是 0 ~ 20 之间的值,包括 0 和 20,有些实现可以支持更大的数值范围.如果省略了该参数,将用 0 代替. 返回值 返回 NumberObject 的字符串表示,不采用指数计数法,小数点后有固定的 num 位数字.如果必要,该数字会被舍入,也可以用 0 补足,以便它达到指定的长度.如果 num 大于 l

  • JavaScript中关键字 in 的使用方法详解

    for-in循环应该用在非数组对象的遍历上,使用for-in进行循环也被称为"枚举". 对于数组 ,迭代出来的是数组元素 但不推荐,因为不能保证顺序,而且如果在Array的原型上添加了属性,这个属性也会被遍历出来,所以 最好数组使用正常的for循环,对象使用for-in循环 对于对象 ,迭代出来的是对象的属性: var obj = { "key1":"value1", "key2":"value2", &q

  • 在Android中使用WebSocket实现消息通信的方法详解

    前言 消息推送功能可以说移动APP不可缺少的功能之一,一般简单的推送我们可以使用第三方推送的SDK,比如极光推送.信鸽推送等,但是对于消息聊天这种及时性有要求的或者三方推送不满足业务需求的,我们就需要使用WebSocket实现消息推送功能. 基本流程 WebSocket是什么,这里就不做介绍了,我们这里使用的开源框架是https://github.com/TakahikoKawasaki/nv-websocket-client 基于开源协议我们封装实现WebSocket的连接.注册.心跳.消息分

  • javascript解析json格式的数据方法详解

    JSON (JavaScript Object Notation)是一种简单的数据格式,比xml更轻巧. 它是 JavaScript 原生格式,这意味着在 JavaScript 中处理 JSON 数据不需要任何特殊的 API 或工具包.那么如何用JavaScript来解析json呢? 首先,科普一下json.在json中,有两种结构:对象和数组. 一个对象以"{"(左括号)开始,"}"(右括号)结束.每个"名称"后跟一个":"

  • javascript读取本地文件和目录方法详解

    JavaScript是网页制作中离不开的脚本语言,依靠它,一个网页的内容才生动活泼.富有朝气.但也许你还没有发现并应用它的一些更高级的功能吧?比如,对文件和文件夹进行读.写和删除,就象在VB.VC等高级语言中经常做的工作一样.怎么样,你是否需要了解这方面的知识?那就请跟我来,本文将详细描述如何使用Javascript语言进行文件操作. 一.功能实现核心:FileSystemObject 对象 其实,要在Javascript中实现文件操作功能,主要就是依靠FileSystemobject对象.在详

  • JavaScript实现拖拽排序的方法详解

    目录 实现原理概述 代码实现 完整代码实现 可拖拽排序的菜单效果大家想必都很熟悉,本次我们通过一个可拖拽排序的九宫格案例来演示其实现原理. 先看一下完成效果: 实现原理概述 拖拽原理 当鼠标在[可拖拽小方块](以下简称砖头)身上按下时,开始监听鼠标移动事件 鼠标事件移动到什么位置,砖头就跟到什么位置 鼠标抬起时,取消鼠标移动事件的监听 排序原理 提前定义好9大坑位的位置(相对外层盒子的left和top) 将9大砖头丢入一个数组,以便后期通过splice方法随意安插和更改砖头的位置 当拖动某块砖头

  • JavaScript生成UUID的五种方法详解

    目录 简介 1.第一种 2.第二种 3.第三种 4.第四种 5.第五种 简介 UUID(Universally Unique IDentifier) 全局唯一标识符. UUID是一种由算法生成的二进制长度为128位的数字标识符.UUID的格式为“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,其中的 x 是 0-9 或 a-f范围内的一个32位十六进制数.在理想情况下,任何计算机和计算机集群都不会生成两个相同的UUID. 1.第一种 function guid() {

随机推荐