ZhangYang's Blog

Promise解决回调地狱

从回调到Promise

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>异步demo</title>
</head>
<body>
用户: <span id="user"></span>
<hr>
分组: <span id="groups"></span>
<hr>
其中第一个群含有成员: <span id="members"></span>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="./main.js"></script>
</body>
</html>
// user.json
{
"name": "zhangyang",
"id": 1
}
// group.json
[
{"name": "11班","id": 1},
{"name": "12班","id": 2}
]
// group_member.json
[
{"name": "张扬","id": 11},
{"name": "张琴","id": 21}
]
// main.js
$.ajax({
url: './user.json',
method: 'get',
success: onGetUser,
error: onError
})
function onGetUser(data){
$('#user').text(data.name)
$.ajax({
url: './group.json?id=' + data.id,
method: 'get',
success: onGetGroup,
error: onError
})
}
function onGetGroupMember(data){
$('#members').text([data[0].name, data[1].name].join(','))
}
function onError(){
alert('服务器繁忙,你先去一边儿待着')
}
function onGetGroup(data){
$('#groups').text([data[0].name, data[1].name].join(','))
$.ajax({
url: './group_member.json?group_id=' + data[0].id,
method: 'get',
success: onGetGroupMember,
error: onError
})
}
// main-promise.js
// Promise解决上述回调地狱,使代码优美
$.get('./user.json').then(function(data){
$.get('./group.json?id=' + data.id).then(function(data){
$.get('./group_member.json?group_id=' + data[0].id).then(function(){
console.log('成功')
},onError)
},onError)
},onError)
function onError(){
console.log('被雷劈')
}

创造一个Promise对象

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
// 普通异步函数
function rollDice(callback){
setTimeout(function(){
console.log('开始摇')
let random = Math.random()
if(random > 0.5){
callback('大')
}else{
callback('小')
}
})
}
let result = rollDice(function(data){
console.log(data)
})
// promise-marker.js
function rollDice(){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log('开始摇')
let random = Math.random()
if(random > 0.5){
resolve('大')
}else{
resolve('小')
}
},1000)
})
}
let result = rollDice()
result.then(function(bigOrSmall){
console.log(bigOrSmall)
})

Promise实际使用场景

Promise + ajax场景一

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
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>异步demo</title>
</head>
<body>
用户: <span id="user"></span>
<hr>
分组: <span id="groups"></span>
<hr>
其中第一个群含有成员: <span id="members"></span>
<form action="./user.json" method="post">
<input type="text" name="username" placeholder="username">
<input type="text" name="password" placeholder="password">
<input type="submit" value="提交">
</form>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="./main.js"></script>
</body>
</html>
// main.js
$('form').on('submit',function(e){
e.preventDefault()
$('form input[type=submit]').prop('disabled',true)
getUser()
.then(data => {
$('form input[type = submit]').prop('disabled',false)
})
})
function getUser(){
return $.post('./user.json',{username: 'xxx'})
.then(data => {console.log(data)},xhr => {alert('error')})
}

Promise + ajax场景二

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// 原生ajax版本
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ajax原生版本</title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<div id="div1"><h2>使用 jQuery AJAX 修改文本内容</h2></div>
<button>获取其他内容</button>
<script>
$(document).ready(function(){
$("button").click(function(){
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && (xhr.status === 200 || xhr.status === 304)){
var results = xhr.responseText
$("#div1").html(results);
}
}
xhr.open('get', 'demo_test.txt',true)
xhr.send()
});
});
</script>
</body>
</html>
// promise版本
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>promise版本</title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<div id="div1"><h2>使用 jQuery AJAX 修改文本内容</h2></div>
<button>获取其他内容</button>
<script>
$(document).ready(function(){
$("button").click(function(){
function ajaxPromise(param){
return new Promise((resovle, reject) => {
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200 || xhr .status === 304) {
var result = xhr.responseText;
resovle(result);
}else{
var error = xhr.responseText;
reject(error);
}
}
}
xhr.open(param.type, param.url, true);
xhr.send();
})
}
var p = ajaxPromise({
url:"demo_test.txt",
type: "get"
})
p.then(function(value){
$("#div1").html(value);
})
});
});
</script>
</body>
</html>

一个错误的Promise实现

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
// new Promise(function(resolve,reject){})
// myPromise.js
function myPromise(fn){
let status = 'waiting'
this.successFnList = []
this.failFnList = []
let resolveFn = (value) => {
status = 'fulfilled'
for(let i = 0; i < this.successFnList.length; i++){
let successFn = this.successFnList[i]
successFn.call(undefined,value)
}
}
let rejectFn = (reason) => {
status = 'rejected'
for(let i = 0; i < this.failFnList.length; i++){
let failFn = this.failFnList[i]
failFn.call(undefined,reason)
}
}
fn.call(undefined,resolveFn,rejectFn)
}
myPromise.prototype.then = function(success,fail){
success && this.successFnList.push(success)
fail && this.failFnList.push(fail)
}
// promise使用
let p = new myPromise(function(resolve,reject){
setTimeout(function(){
resolve('big')
},1000)
})
p.then(function(data){
console.log('fn1: ' + data)
},function(error){
console.log('fn2: ' + error)
})