14.Promise

 

Promise

Promise是ES6引入的异步编程的新解决方案。

语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。

1
2
3
1.Promise构造函数:Promise(executor(){})
2.Promise.prototype.then()
3.Promise.prototype.catch()

1.基本示例

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise basic syntax</title>
</head>
<body>
<script>
/**
* create a Promise instance p by use new Promise(function(resolve, reject) {});
* new Promise() receive a function as parameter,
* the first parameter of the function is usually named resolve,
* the second parameter of the function is usually named reject.
* We can use function resolve() and reject() to setup the status of instance p,
* When the function execute successfully, use the resolve() to update status to success.
* When the function execute failed, use the reject() to update status to fail.
*/
const p = new Promise(function(resolve, reject) {
setTimeout(function() {
// resolve
// let data = 'user data in database';
// resolve(data);

// reject
let err = 'read the data failed';
reject(err);
}, 1000);
});

/**
* then() has two parameters that are two functions.
* The first function will execute when the resolve() function executed,
* The second function will exxcute when the reject() function executed,
* parameters can be transferred
*/
p.then(function(value) {
console.log(value);
// user data in database
}, function(reason) {
console.log(reason);
// read the data failed
});
</script>
</body>
</html>

2.使用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
/**
* import fs module
*/
const fs = require('fs');
/**
* 1.common
*/
fs.readFile('./resources/为学.md', (err, data) => {
if(err) {
throw err;
/*
[Error: ENOENT: no such file or directory, open 'E:\VSCode\workspace\shangguigu\frontend\ES6-ES11\ES6\promise\resources\为学1.md'] {
errno: -4058,
code: 'ENOENT',
syscall: 'open',
}
*/
}
console.log(data);
/*
<Buffer 20 20 20 e4 b8 ba e5 ad a6 0d 0a e5 a4 a9 e4 b8 8b e4 ba 8b e6 9c 89 e9 9a be e6 98 93 e4 b9 8e ef bc 9f 0d 0a e4 b8 ba e4 b9 8b ef bc 8c e5 88 99 e9 ... 46 more bytes>
*/

console.log(data.toString());
/*
为学
天下事有难易乎?
为之,则难者亦易矣;
不为,则易者亦难矣
*/
});

/**
* 2.promise
*/
const p = new Promise(function(resolve, reject) {
fs.readFile('./resources/为学1.md', function(err, data) {
if(err) {
reject(err);
} else {
resolve(data.toString());
}

})
});

p.then(function(value) {
console.log(value);
/*
为学
天下事有难易乎?
为之,则难者亦易矣;
不为,则易者亦难矣
*/
}, function(reason) {
console.log(reason);
/*
[Error: ENOENT: no such file or directory, open 'E:\VSCode\workspace\shangguigu\frontend\ES6-ES11\ES6\promise\resources\为学1.md'] {
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: 'E:\\VSCode\\workspace\\shangguigu\\frontend\\ES6-ES11\\ES6\\promise\\resources\\为学1.md'
}
*/
})

3.Promise发送Ajax请求(w)

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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>promise send ajax request</title>
</head>

<body>
<script>
const p = new Promise(function(resolve, reject) {
// 1.创建对象
const xhr = new XMLHttpRequest();
// 2.初始化
xhr.open("GET", "https://api.apiopen.top/getJoke");
// 3.发送
xhr.send();
// 4.绑定事件,处理相应结果
xhr.onreadystatechange = function() {
// 判断
if(xhr.readyState === 4) {
// 成功响应码为200-299
if(xhr.status >= 200 && xhr.status < 300) {
// console.log(xhr.response);
resolve(xhr.response);
} else {
// console.log(xhr.status);
reject(xhr.status);
}
}
};
});

p.then(function(value) {
console.log(value);
}, function(reason) {
console.log(reason);
});

</script>
</body>

</html>

4.then()

PromiseState的状态一共有3种:

  1. pending:未决定、初始、准备状态
  2. fulfilled / resolved(不同浏览器显示的不一样):成功
  3. rejected:失败
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
85
86
87
88
89
90
91
92
93
94
95
96
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise.prototype.then</title>
</head>
<body>
<script>
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('用户数据');
// reject('出错了');
}, 1000);
})

/**
* then()方法的返回值为Promise对象,Promise对象的状态取决于回调函数的返回值
*/
const result = p.then((value) => {
console.log(value);
/**
* 1.回调函数返回值不是Promise对象,then()方法的返回值Promise对象:
* PromiseState = "fulfilled"
* PromiseResult = 回调函数返回值
*/
return 123;
/*
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: 123
*/

/**
* 2.回调函数返回值是Promise对象,then()方法的返回值Promise对象:
* PromiseState =
* (1)返回的Promise对象调用resolve(),PromiseState = "fulfilled"
* (2)返回的Promise对象调用reject(),PromiseState = "rejected"
* PromiseResult = 回调函数返回值
*/
return new Promise((resolve, reject) => {
resolve('ok');
/*
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: "ok"
*/

reject('fail');
/*
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: "fail"
*/
});

/**
* 3.回调函数抛出错误,then()方法的返回值Promise对象:
* PromiseState = "rejected"
* PromiseResult = 错误信息
*/
throw new Error('发生错误');
/*
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: Error: 发生错误 at file:///E:/VSCode/workspace/shangguigu/frontend/ES6-ES11/ES6/promise/26_promise_then.html:63:19
*/
throw '出错了';
/*
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: "出错了"
*/
}, (reason) => {
console.log(reason);
})

console.log(result);

/**
* 链式编程
* then()方法的参数可以只写成功的处理函数
*/
p.then((value) => {

}).then((value) => {

});
</script>
</body>
</html>

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
// import fs module
const fs = require("fs");

// 1.common
fs.readFile("./resources/为学.md", (err, data1) => {
fs.readFile("./resources/插秧诗.md", (err, data2) => {
fs.readFile("./resources/观书有感.md", (err, data3) => {
let result = data1 + "\n" + data2 + "\n" + data3;
console.log(result);
})
})
})

// 2.promise execute multiple asynchronous task
const p = new Promise((resolve, reject) => {
fs.readFile("./resources/为学.md", (err, data) => {
resolve(data.toString());
})
})

p.then((value) => {
return new Promise((resolve, reject) => {
fs.readFile("./resources/插秧诗.md", (err, data) => {
resolve([value, data]);
})
});
}).then((value) => {
return new Promise((resolve, reject) => {
fs.readFile("./resources/观书有感.md", (err, data) => {
value.push(data);
resolve(value);
})
})
}).then((value) => {
console.log(value.join("\n"));
/*
三个文件的内容
*/
})

6.catch()

catch()方法与then(..., (reason) => {})方法功能相同,处理失败情况

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>catch方法</title>
</head>
<body>
<script>
const p = new Promise((resolve, reject) => {
setTimeout(function(){
reject("io error");
}, 1000);
});

// 1.then((value) => {}, (reason) => {})
p.then((value) => {}, (reason) => {
console.log(reason);
});

// 2.catch((reason) => {})
p.catch((reason) => {
console.log(reason);
});
</script>
</body>
</html>