优化AJAX的JS封装代码

为了一步步地理清封装步骤,我打算逐步封装ajax函数的功能,分成了以下6个版本:

Version 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    function ajax (method, url, params) {
xhr.open(method, url)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') //针对post的设置请求头

params = params || null

xhr.send(params)
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return
console.log(this.responseText)
}
}

ajax('GET','xxx.php','id=1');
ajax('POST','xxx.php','key1=value1&key2=value2');

说明:

  • 未兼容低版本 IE
  • 这种方法在传参数的时候只能上例所示的格式,无法用json格式;
  • 当method为get的时候,参数没正确地加在url后面无法起到作用;
  • method为get时也是设置了(‘Content-Type’, ‘application/x-www-form-urlencoded’)的请求头,但是这是不必要的。
  • 把函数的结果写死了,总是console.log(this.responseText)



Version 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    function ajax (method, url, params) {
method = method.toUpperCase() //统一为大写,避免实参为小写的情况造成下面匹配时出错

//解决XMLHttpRequest在ie6不兼容的问题
var xhr = null;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else {
xhr = new ActiveXObject('Microsoft.XMLHttp');
}

if (method === 'GET') {
url += '?' + params
}

xhr.open(method, url)

var data = null
if (method === 'POST') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
data = params
}

xhr.send(data)
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return
console.log(this.responseText)
}
}

ajax('GET','xxx.php','id=1');
ajax('POST','xxx.php','key1=value1&key2=value2');

说明:

  • 实现了IE低版本的兼容并实现了method各自对应的传参方式
  • 这种方法在传参数的时候只能上例所示的格式,无法用json格式;
  • 把函数的结果写死了,总是console.log(this.responseText)



Version 3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
    function ajax (method, url, params) {
method = method.toUpperCase()
var xhr = null;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else {
xhr = new ActiveXObject('Microsoft.XMLHttp');
}

// 将 object 类型的参数转换为 key=value&key=value
if (typeof params === 'object') {
var tempArr = []
for (var key in params) {
var value = params[key]
tempArr.push(key + '=' + value)
}
// tempArr => [ 'key1=value1', 'key2=value2' ]
params = tempArr.join('&')
// params => 'key1=value1&key2=value2'
}

if (method === 'GET') {
url += '?' + params
}

xhr.open(method, url)

var data = null
if (method === 'POST') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
data = params
}

xhr.send(data)
xhr.onreadystatechange = function () {
if (this.readyState !== 4) return
console.log(this.responseText)
}
}

ajax('GET','xxx.php','id=1');
ajax('POST','xxx.php','key1=value1&key2=value2');
ajax('GET', 'time.php', { id: 1 })
ajax('POST', 'add.php', { key1: 'value1', key2: 'value2' })

说明:

  • 弥补了无法使用json传参的缺陷,既能用字符串形式传参也能用json
  • 仍然把函数结果写死了



尝试在Ajax中return出数据



Version 4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
    function ajax (method, url, params) {
var res = null //用于返回值

method = method.toUpperCase()
var xhr = null;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else {
xhr = new ActiveXObject('Microsoft.XMLHttp');
}

// 将 object 类型的参数转换为 key=value&key=value
if (typeof params === 'object') {
var tempArr = []
for (var key in params) {
var value = params[key]
tempArr.push(key + '=' + value)
}
// tempArr => [ 'key1=value1', 'key2=value2' ]
params = tempArr.join('&')
// params => 'key1=value1&key2=value2'
}

if (method === 'GET') {
url += '?' + params
}

xhr.open(method, url, false) //async参数为false,使用同步而非异步

var data = null
if (method === 'POST') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
data = params
}

xhr.onreadystatechange = function () {
if (this.readyState !== 4) return
// 不应该在封装的函数中主观的处理响应结果
// console.log(this.responseText)
// 无法在内部包含的函数中通过 return 给外部函数的调用返回结果
// return this.responseText
// 由于异步模式下 这里的代码最后执行 所以不可能在外部通过返回值的方式返回数据
res = this.responseText
}

xhr.send(data) //使用了同步的策略,只能把send()置于最后

return res
}

var result = ajax("GET","xxx.php",{id: 1});
var result2 = ajax("POST","xxx.php",{key1: 'value1', key2: 'value2'});
console.log(result);
alert(result2);

说明:

  • 函数有返回值,没有把函数写死
  • 但是使用了同步的策略,这是非常不好的



Version 5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  // 封装者
// =============================

function ajax (method, url, params, done) {
method = method.toUpperCase()
var xhr = null;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else {
xhr = new ActiveXObject('Microsoft.XMLHttp');
}

if (typeof params === 'object') {
var tempArr = []
for (var key in params) {
var value = params[key]
tempArr.push(key + '=' + value)
}
params = tempArr.join('&')
}

if (method === 'GET') {
url += '?' + params
}

xhr.open(method, url, true)//async默认为true,即为异步策略

var data = null
if (method === 'POST') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
data = params
}

xhr.onreadystatechange = function () {
if (this.readyState !== 4) return
// 不应该在封装的函数中主观的处理响应结果
// console.log(this.responseText)
// 你说我太主观,那么你告诉我应该做什么
done(this.responseText)
}

xhr.send(data)
}

// 调用者
// ============================

var onDone = function (res) {
console.log(res)

}

ajax('get', 'time.php', {}, onDone)

说明:

为什么return出来的是undefined?为什么取不出一个正确的return值?因为Ajax是异步的操作,在获取数据完成之前,就已经执行了return res(计划中获取到的数据),所以是无法正确return出我们想要的结果的。

既然取不出一个return值,那么换个思路,使用回调函数让封装者替我们实现我们想要的效果.

使用的是异步策略,在异步的情况下使用回调函数时比较多的。

但是这段代码还是比较凌乱的



Version 6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
function ajaxFunc(method,url,data,callback,flag){
flag = flag||true;//默认采用异步模式
method = method.toUpperCase();
var xhr = null;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else {
xhr = new ActiveXObject('Microsoft.XMLHttp');
}

//当参数以json格式传入时,转化成字符串&格式
if (typeof data === 'object') {
var tempArr = []
for (var key in data) {
var value = data[key]
tempArr.push(key + '=' + value)
}
data = tempArr.join('&')
}


if(method == 'GET'){
url +=('?'+ data);
xhr.open(method,url,flag);
xhr.send();

}else if(method == 'POST'){
xhr.open(method,url,flag);
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xhr.send(data);
}

xhr.onreadystatechange = function(){
if(this.readyState == 4){
if(this.status == 200){
callback(this.responseText);
}else {
console.log("ERROR!");
}
}
}

}
//测试代码:
ajaxFunc('GET', 'post.php', "", myfun1, true);
ajaxFunc('POST', 'post.php', "username=jiji&age=450", myfun2, true);
ajaxFunc('POST', 'post.php', {username: 'jiji',age: 45}, myfun2, true);

这个是Ajax比较像样的封装函数了。



(完)