HTTP协议(HyperText Transfer Protocol)全称超文本传输协议,是因特网上最广泛的一种网络传输协议,基于TCP/IP协议传输数据。
HTTP基于客户端服务端模式,一次HTTP事务处理过程如下:
Step1:客户端与服务端建立连接
Step2:客户端向服务端发出请求
Step3:服务端接受请求,并根据请求返回响应的数据信息作为响应
Step4:客户端接受服务端响应
Step5:客户端与服务端关闭连接
HTTP请求报文包含如下内容:
HTTP响应报文包含以下内容
状态码 | 描述 |
---|---|
100~199 | 信息,服务器收到请求,需要请求者继续执行操作 |
200~299 | 成功,操作被成功接收并处理 |
300~399 | 重定向,需要进一步的操作以完成请求 |
400~499 | 客户端错误,请求包含语法错误或无法完成请求 |
500~599 | 服务器错误,服务器在处理请求的过程中发生了错误 |
常见状态码:
{
"id":100,
"username":"BH13",
"age":21,
"sex":"male",
"isLogin":true,
"girlfriend":null,
"ex-girlfriend":[
{
"name":"Ada",
"age":20
},
{
"name":"Bella",
"age":18
},
{
"name":"Cherry",
"age":30
}
],
"什么情况":"你变成方块字啦"
}
JavaScript有一个内置对象JSON,用于处理JSON数据
var json = {
name:'BH13',
age:20,
中文名:'不便透露'
}
var jsonstr = JSON.stringify(json);
var jsonobj = JSON.parse(jsonstr);
console.log(jsonstr);
console.log(jsonobj);
客户端将数据存储在cookie中,cookie会放在请求头中随着HTTP请求发送给服务端,由服务端解析数据。同样服务端可以产生cookie,发送给客户端,客户端接收到cookie后保存在本地
传统的jsp,php等服务端语言,在页面内设置form表单,确定需要传递的参数,通过submit传输到服务器
下面是一个通过form表单访问快递鸟打印接口的例子:
<form id="form1"
action="http://www.kdniao.com/External/PrintOrder.aspx"
method="post"
target="_self">
<div>
<input type="text" id="RequestData" name="RequestData">请求数据
div>
<div>
<input type="text" id="DataSign" name="DataSign"/>签名
div>
<div>
<input type="text" id="EBusinessID" name="EBusinessID"/>商户id
div>
<div>
<input type="text" id="IsPreview" name="IsPreview" value="1"/>
<span style="color: red;">是否预览 0-不预览 1-预览span>
div>
<div>
<input type="submit" value="打印" />
div>
form>
下一节会进行详解
js实现:
//指定的回调函数
function getData(data){
console.log(data)
}
//动态创建script标签
function addScript(){
var url = 'http://localhost:9000/server.js?callback=getData';
var script = document.createElement('script');
script.src = url;
var body = document.getElementsByTagName('body')[0];
body.appendChild(script);
}
jQuery实现:
$.ajax({
type:'get', //强制把get改为post,最后发现还是get
url:'http://localhost:9000/server.js',
dataType:'jsonp',
jsonp: "callback", //指定路径里的参数名
jsonpCallback:"getData", //指定回调函数名
success: function(data){
console.log(data);
},
error: function(){
console.log('请求出错')
}
})
JSONP弊端:
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
AJAX相当于是在用户和服务器之间加了—个中间层(AJAX引擎),使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器,像—些数据验证和数据处理等都交给 Ajax引擎自己来做, 只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。
创建AJAX对象
var xhr = new ActiveXObject('Microsoft.XMLHTTP'); //ie6以下
var xhr = new XMLHttpRequest();
使用AJAX对象的方法
xhr.open(method,url,async, username, password) //设置请求基本信息
xhr.setRequestHeader(header, value) //设置请求头
xhr.onreadystatechange() //监听readyState属性
xhr.getResponseHeader() //获得响应头
xhr.ontimeout() //请求超时后的回调函数
xhr.send() //发送请求
使用AJAX对象的属性
xhr.readyState
:获得请求的状态
xhr.status
:获得HTTP响应的状态码
xhr.responseText
:获得服务器返回的文本数据
xhr.responseXML
:获得服务器返回的一个XML数据
xhr.timeout
:设置请求的超时时间(ms)
readyState取值:
readyState | 描述 |
---|---|
0 | 请求未初始化 |
1 | 服务器连接已建立 |
2 | 请求已接收 |
3 | 请求处理中 |
4 | 请求已完成,且响应已就绪 |
一段完整的使用AJAX的实例:
function requestServer(sendData){
var xhr;
if (window.XMLHttpRequest)
{
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xhr = new XMLHttpRequest();
}
else
{
// IE6, IE5 浏览器执行代码
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
//开启xhr请求,下面的url是博主的一个测试地址
xhr.open('post', 'http://localhost:9000/server.js', true);
//设置超时时间为10s
xhr.timeout = 10000;
//设置请求头的content-type
xhr.setRequestHeader('content-type', 'application/json;charset-UTF-8');
//监听readyState的变化
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
// 请求成功的后续处理写在下面
console.log('request success');
if(xhr.responseText){
console.log(JSON.parse(xhr.responseText)); //接收后端传过来的数据
}
else{
console.log(xhr.responseXML); //接收后端传来的XML格式的数据
}
}
}
//超时后调用的函数
xhr.ontimeout = function(e){
console.log('request timeout');
}
//发送数据
xhr.send(JSON.stringify(sendData))
}
jQuery中的AJAX
jQuery对AJAX做了较为完善的封装
最底层:$.ajax()
第二层:$.load(), $.get(), $.post()
第三层:$.getScript(), $.getJSON()
$.ajax({
url:'http://localhost:9000/server.js', //请求地址
headers:{
'token':token,
}, //设置请求头
type:'post', //请求方法
timeout:10000, //请求的超时时间
data:JSON.stringify(sendData), //发送给服务端的数据
dataType:'json', //预期服务器返回的数据
contentType:'application/json;charset-UTF-8', //设置请求头中的contentType
complete:function(xhr, textStatus){
console.log(xhr, textStatus)
},//请求完成的回调函数
success:function(data, textStatus){
console.log(data, textStatus); //data即为服务器返回的数据
}, //请求成功并且服务器响应成功的回调函数
error:function(xhr, textStatus, errorThrown){
console.log(xhr,textStatus, errorThrown);
} //请求失败时的回调函数
})
一个域名地址如下:
http://www.billhao.com:8080/web/index.html
协议,主域名,子域名,端口号(默认80端口),任意一个不相同时,都叫跨域
同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出请求后服务端发回的数据,即请求发送了,服务器响应了,但是无法被浏览器接收。
同源策略会造成:
cookie、localStorage和IndexDB无法读取
DOM无法获得
AJAX请求不能发送
注:所谓同源是指,域名,协议,端口相同。
单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。JavaScript作为浏览器脚本语言决定了他必须是单线程执行,否则会造成某些处理产生冲突。
对于客户端页面来说,如果所有的操作都是单线程同步的,极易造成页面的阻塞,因此,异步机制是必须的。JavaScript是单线程,它是同步执行的是无可争议的,但是浏览器内核是异步的,通过浏览器内核的异步调度处理,JavaScript有自己实现异步的方法,即事件循环(event loop):
1.所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)
2.主线程之外,还存在一个任务队列(task queue),只要异步任务有了运行结果,就在“任务队列”之中放置一个事件,不同的异步操作添加到任务队列的时机也不同
3.一旦“执行栈”中的所有同步任务执行完毕,系统就会读取“任务队列”,看看里面有哪些事件。那些对应的异步任务,就结束等待状态,进入执行栈开始被执行。
4.循环执行 上述三步
一个经典实例:
console.log(1);
setTimeout(function(){
console.log(2);
}, 0);
console.log(3);
//执行结果1, 3, 2
给script标签加defer属性
这是IE浏览器独有的方法,这种方法也可以直接在script标签里写入代码
给script标签加aysnc属性
这个方法无法在script标签里写入js代码
动态加载script标签
function addScript(){
var script = document.createElement('script');
script.type = "text/javascript";
script.src = "demo.js";
docuemnt.head.appendChild(script);
}
所谓模块化开发,是指将一个项目按照功能划分,理论上一个功能一个模块,互不影响,在需要的时候载入,尽量遵循高内聚低耦合
function fun1(){
}
function fun2(){
}
缺陷:所有模块都暴露在全局对象中。
var mod = {
__cnt__ = 0,
fun1:function(){
},
fun2:function(){
}
}
缺陷:mod内的变量可以直接通过mod.__cnt__
访问到:
var mod = (function(){
var __cnt__ = 0;
var fun1 = function(){
};
var fun2 = function(){
};
return {
fun1:fun1,
fun2:fun2
};
})
这样写就避免了__cnt__
在外部被访问
下面的代码实现了为mod扩展了一个模块
var mod = (function(){
var __cnt__ = 0;
var fun1 = function(){
};
return {
fun1:fun1
};
})()
mod = (function(m){
m.fun2 = function(){
};
return m;
})(mod)
输入全局变量
为一个模块引入一些全局变量供模块使用,例如将一些js库定义的全局变量导入
var mod = (function($, cptable){
})(jQuery, cptable);
传统的引入多个模块方式
<script src="a.js">script>
<script src="b.js">script>
<script src="c.js">script>
缺陷:增加了页面加载脚本文件的压力,对于耦合性高的不同模块之间,需要有严格的执行顺序,而且易造成变量冲突。
AMD规范
AMD(Asynchronous Module Definition)采用异步加载模块,模块的加载不影响后面语句的运行,所有依赖此模块的语句,都定义在一个回调函数中,当模块加载完成,执行回调函数。
实现语法:
require(module, callback)
RequireJS
RequireJS是一个实现了AMD规范的js模块加载库,它有以下优势:
异步加载:RequireJS是异步加载模块,模块加载完毕执行回调函数,避免了页面的阻塞
按需加载:当需要某个模块时,他才会去加载
依赖管理:RequireJS的机制保证了加载完所有依赖模块后才会去执行相关逻辑
版本管理:只需更改引入模块处的地址信息就可以控制模块版本的更换
使用RequireJS只需在页面中引入require.js,然后再引入main.js,接着再对main.js进行配置
require.config({
paths:{
"jquery":'../lib/jquery.min'
}//配置引入模块的路径
});
require(['jquery'],function($){
//在此写jQuery代码
})//第一个参数是引入模块的列表,第二个参数是回调函数
CommonJS是适用于服务端开发的一个模块规范,它是同步加载模块,Node.js的模块系统参照CommonJS规范定制,并不适用于浏览器开发。
//mod1.js:导出default模块
export default function(){
};
//mod2.js:直接导出模块
export function mod(){
};
//mod3.js:统一导出模块
var num = 1;
var arr = [1,2,3];
var obj = {
name:'BH13',age:20};
function mod3(){
}
export {
num, arr, obj, mod3}
import mod1 from 'mod1.js' //导入由export default导出的模块
import {
mod as mod2} from 'mod2.js' //将导入的模块名称重新命名
import {
num, arr, obj, mod3} from 'mod3.js' //导入指定了名称的模块
模块化开发详细内容可以看一看这个博客:
阮一峰的网络日志:Javascript模块化编程(一):模块的写法