这一次,彻底弄懂 Promise 原理
1.为什么需要 promise
需求
通过 AJAX 请求 id ,再根据 id 请求用户名.再根据用户名,再根据用户名获取 email
回调地狱
回调函数中嵌套回调
Promise 解决了回调地狱
2.promise 的基本使用
promise 是一个构造函数,通过 new 关键字实例化对象
语法
new Promise((resolve, reject) => {});
1
- Promise 接受一个函数作为参数
- 在参数函数中接受两个参数
- resolve:成功函数
- reject:失败函数
promise 实例
promise 实例有两个属性
- state:状态
- result:结果
1)Promise 的状态
第一种状态:pending(准备,待解决,进行中)
第二种状态:fulfilled(已完成,成功)
第三种状态:rejected(已拒绝,失败)
2.Promise 状态的改变
实例 1
const p = new Promise((resolve, reject) => {
//resolve(): 调用函数, 使当前Promise对象的状态改成fulfilled
reslove();
});
console.dir(p); // fulfilled
1
2
3
4
5
2
3
4
5
实例 2
const p = new Promise((resolve, reject) => {
//resolve(): 调用函数, 使当前Promise对象的状态改成fulfilled
//reject(): 调用函数, 使当前Promise对象的状态改成rejected
//reslove();
reject();
});
console.dir(p);
1
2
3
4
5
6
7
2
3
4
5
6
7
- resolve():调用函数,使当前 Promise 对象的状态改成 fulFilled
- reject():调用函数,使当前 Promise 对象的状态改成 rejected
Promise 是一次性的,也就是说,如果你调用了 resolve 或者 reject 这个 Promise 会处理相关回调,然后它的生命周期就结束了。
3) prmoise 的结果
实例
const p = new Promise((resolve, reject) => {
// 通过调用resolve || reject 函数 ,传递的参数,改变的是当前promise对象的结果
// resolve("成功的结果");
reject("失败的结果");
});
console.dir(p);
1
2
3
4
5
6
2
3
4
5
6
3.Promise 方法
1)then 方法
实例
<script>
const p = new Promise((resolve, reject) => {
// 通过调用resolve || reject 函数 ,传递的参数,改变的是当前promise对象的结果
// resolve("成功的结果");
reject("失败的结果");
});
// then 方法函数
// 参数
// 两个参数都是函数
// 返回值:是一个Promise对象
p.then(
() => {
// 当promise状态是fulfilleds时,执行
console.log("成功时的调用");
},
() => {
// 当promise状态是rejected时,执行
console.log("失败时调用");
}
);
console.dir(p);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
实例 2
<script>
const p = new Promise((resolve, reject) => {
// 通过调用resolve || reject 函数 ,传递的参数,改变的是当前promise对象的结果
// resolve("成功的结果");
// resolve("123");
reject("失败的结果");
});
// then 方法函数
// 参数
// 两个参数都是函数
// 返回值:是一个Promise对象
p.then(
(value) => {
// 当promise状态是fulfilleds时,执行
console.log("成功时的调用", value);
// console.log();
},
(err) => {
// 当promise状态是rejected时,执行
console.log("失败时调用", err);
}
);
console.dir(p);
</script>
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- 在 then 方法的函数中,通过形参使用 promise 对象的结果
then 方法返回一个新的 promise 实例,状态时 pending
<script>
const p = new Promise((resolve, reject) => {
// 通过调用resolve || reject 函数 ,传递的参数,改变的是当前promise对象的结果
// resolve("成功的结果");
// resolve("123");
reject("失败的结果");
});
// then 方法函数
// 参数
// 两个参数都是函数
// 返回值:是一个Promise对象
const t = p.then(
(value) => {
// 当promise状态是fulfilleds时,执行
console.log("成功时的调用", value);
// console.log();
},
(err) => {
// 当promise状态是rejected时,执行
console.log("失败时调用", err);
}
);
console.dir(p);
</script>
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
promise 的状态不改变,不会执行 then 里的方法
// 如果promise 的状态不改变 then里的方法不会执行
const p = new Promise((resolve, reject) => {}).then(
(value) => {
console.log("成功");
},
(err) => {
console.log("失败");
}
);
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
在 then 方法中,通过 return 将返回的 promise 的状态
//如果Promise的状态改变,then里的方法不会执行
const p = new Promise((resolve, reject) => {
})
const t = p.then((value) => {
console.log("成功")
//使用return可以将t实例的状态改为fulfilled
return 123
},(reason) => {
console.log("失败")
})
t.then.((value) => {
console.log("成功2",value)
},(reason) => {
console.log("失败2")
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在 then 方法中,出现代码错误,将返回的 Promise 实例改为 rejected 状态
//如果Promise的状态改变,then里的方法不会执行
const p = new Promise((resolve, reject) => {
})
const t = p.then.((value) => {
console.log("成功")
//使用return可以将t实例的状态改为fulfilled
return 123
},(reason) => {
//如果这里代码出错,会将t实例的状态改为rejected
console.log("失败")
})
t.then.((value) => {
console.log("成功2",value)
},(reason) => {
console.log("失败2")
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2)catch 方法
示例
const p = new Promise((resolve, reject) => {
//reject()
//console.log(a)
throw new Error("出错了");
})
//思考: catch中的参数函数在什么时候被执行
//1. 当Promise的状态改为rejcted.被执行
//2. 当Promise执行过程出现代码错误时,被执行
p.catch((reason => {
console.log("失败", reason)
})
console.log(p);
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
4.优化代码
示例
//封装ajax请求
function getData(url, data = {}){
return new Promise((resolve, reject) => {
$.ajax({
//发送请求类型
type: "GET",
url: url,
data: data,
success: function (res) {
// 修改Promise状态为成功, 修改Promise的结果res
resolve(res)
},
error:function (res) {
// 修改Promise的状态为失败,修改Promise的结果res
reject(res)
}
})
}
}
//调用函数
getData("data1.json")
.then((data) => {
//console.log(data)
const { id } = data
return getData("data2.json", {id})
})
.then((data) => {
//console.log(data)
const { usename } = data
return getData("data3.json", {usename})
})
.then((data) => {
console.log(data)
})
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
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
5.async 和 await
1) async 函数
- 函数的返回值为 promise 对象
- promise 对象的结果由 async 函数执行的返回值决定
示例
async function main(){
//1.如果返回值是一个非Promise类型的数据
// return 一个字符串 数字 布尔值等都是成功的Promise对象
//2. 如果返回的时一个Promise对象
// return new Promise((resolve, reject) => {
//resolve("OK") 返回的是成功Promise对象,状态值:[[PromiseState]]:"fulfilled"
//reject("Err") 返回的是失败Promise对象,状态值:[[PromiseState]]:"rejected"
//3. 抛出异常
throw "oh No" //状态值:[[PromiseState]]:"rejected",结果是抛出的值
})
}
let result = main();
console.log(result);
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
返回值是一个 Promise 对象
2) await 表达式
await 右侧的表达式一般为 promise 对象, 但也可以是其它的值
如果表达式是 promise 对象, await 返回的是 promise 成功的值
如果表达式是其它值, 直接将此值作为 await 的返回值
注意
await 必须写在 async 函数中, 但 async 函数中可以没有 await
如果 await 的 promise 失败了, 就会抛出异常, 需要通过 try...catch 捕获处理
3) async 和 await 结合
示例
const fs = require("fs");
const util = require("util");
const mineReadFile = util.promisify(fs.readFile);//promisify转换为Promise形态的函数
async function main(){
//捕获处理
try{
//读取第一个文件的内容
let data1 = await mineReadFile("./resource/1.html");
let data2 = await mineReadFile("./resource/2.html");
let data3 = await mineReadFile("./resource/3.html");
}catch(e){
console.log(e):
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15