Promise
# 介绍
Promise 是ES6对异步编程
一种解决方案。Promise就是一个对象容器,将异步操作(同步也可以但是没有必要这么做)保存在容器内部,当异步操作执行时就可以Promise获取当前异步操作的消息。这种模式会比传统回调更强大与合理。
Promise 异步操作有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)
。除了异步操作的结果,任何其他操作都无法改变这个状态。
Promise 对象只有:从 pending
变为 fulfilled
和从 pending
变为 rejected
的状态改变。只要处于 fulfilled
和 rejected
,状态就不会再变了即 resolved(已定型)
。
# 基本用法
概念: Promise就是一个构造函数用来生成Promise实例对象
语法: Promise构造函数在生成实例对象时接收一个函数作为参数,该函数接收两个参数(由js引擎所提供)
参数一 resolve 是一个函数它的作用是将Promise 的状态由 pending变为fulfilled (resolve),是一个异步操作执行成功时需要调用的方法
参数二 reject 是一个函数它的作用是将Promise 的状态由 pending变为reject,是一个异步操作执行失败时需要调用的方法 以上两个参数都可以将自身接收的参数传递出去
let p = new Promise(function (resolve, reject) {
let num = Math.random()
if (num > 0.5) {
resolve(num) // 成功调用resolve方法,将num传递出去
} else {
reject('失败了!') // 失败调用reject方法,将'失败了!'传递出去
}
})
2
3
4
5
6
7
8
9
# prototype.then
概念: Promise实例对象生成完毕后可以使用分别制定resolve状态和reject状态的回调函数
语法: then 方法接收两个函数作为参数
参数一 Promise 执行成功时的回调函数,接收resolve传递的参数
参数二 Promise 执行失败时的回调 接收reject传递的参数 两个函数只会有一个被调用。
let p = new Promise(function (resolve, reject) {
let num = Math.random()
if (num > 0.5) {
resolve(num) // 成功调用resolve方法
} else {
reject('失败了!') // 调用reject方法
}
})
p.then(
res => console.log('成功!' + res), // resolve 的回调函数
err => console.error(err) // reject的回调函数
)
2
3
4
5
6
7
8
9
10
11
12
13
14
# prototype.catch
概念: Promise实例对象生成完毕后,当状态 从 pending转换为reject状态时,then方法第二个参数的别名。reject抛出的异常会被catch所捕获
语法:
p.then(
res => console.log('成功!' + res), // resolve 的回调函数
err => console.error(err) // reject的回调函数
)
// 就可以改写为
p.then(res => console.log('成功!' + res) // resolve 的回调函数
.catch(err => console.error(err)) // reject的回调函数
2
3
4
5
6
7
# prototype.finally
概念: 在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。一般做一些异步请求的清理工作。
语法:
p.finally(() => console.log('异步操作执行完毕,无论成功失败') )
p.then(function(json) { })
.catch(function(error) { })
.finally(function() { });
2
3
4
5
# all
概念: 该方法接收多个 promise对象并返回一个 promise对象。多个的 promise 都执行成功后调用promise对象方法
注意 所有的promise都成时 all的状态也是成功;如果有一个Promise失败 all的状态也是失败,失败的原因是第一个失败 promise 的结果。
语法:
function fakeAjax(timeout, name , isSuccess = true) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(isSuccess) {
resolve(name)
}else {
reject(name)
}
}, timeout)
})
}
let p1 = fakeAjax(2500, 'p1')
let p2 = fakeAjax(1500, 'p2')
let p3 = fakeAjax(800, 'p3')
Promise.all([p1, p2, p3])
// 所有Promise都成功才会进入then,
// then的成功回调函数中的参数是一个数组,包含all方法接收多个Promise对象数组成功返回值
.then(res => console.log(res)) // ['p1','p2','p3']
.catch(err => console.error(err) )
let p1 = fakeAjax(2500, 'p1')
let p2 = fakeAjax(1500, 'p2', false)
let p3 = fakeAjax(800, 'p3', false)
// 只要有任何一个Promise失败all就会进入catch
// catch 回调函数接收的参数是第一个失败Promise的返回值
Promise.all([p1, p2, p3])
.then(res => console.log(res))
.catch(err => console.error(err)) // 'p3'
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
# any
概念: 该方法接收多个 promise对象并返回一个 promise对象。多个 promise 只要有一个成功执行就会被调用promise对象方法
注意 如果有一个Promise成功 any就会返回成功,返回的值是第一个成功 promise resolve值。
语法:
function fakeAjax(timeout, name, isSuccess = true) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(name + '执行完毕')
if (isSuccess) {
resolve(name)
} else {
reject(name)
}
}, timeout)
})
}
let p1 = fakeAjax(2500, 'p1')
let p2 = fakeAjax(1500, 'p2')
let p3 = fakeAjax(800, 'p3')
Promise.any([p1, p2, p3])
.then(res => console.log(res)) // 'p3'
.catch(err => console.error(err))
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# race
概念: 该方法接收多个 promise对象并返回一个 promise对象。 只要有一个完成(无论成功失败) 。返回promise对象就会调用完成Promise状态
语法:
let p1 = fakeAjax(2500, 'p1')
let p2 = fakeAjax(1500, 'p2')
let p3 = fakeAjax(800, 'p3', false)
Promise.race([p1, p2, p3])
.then(res => console.log(res))
.catch(err => console.error(err)) // 'p3'
let p1 = fakeAjax(2500, 'p1')
let p2 = fakeAjax(500, 'p2')
let p3 = fakeAjax(800, 'p3')
Promise.race([p1, p2, p3])
.then(res => console.log(res)) // 'p2'
.catch(err => console.error(err))
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# allSettled
概念: 该方法接收多个 promise对象并返回一个 promise对象。必须所有
的Promise都完成(无论成功/失败)该方法才会resolve一个数组
,数组中包含接收所有Promise完成信息(status:成功 fulfilled, 失败 reject,value: 成功返回值,reason:失败原因 ,)
语法:
let p1 = fakeAjax(2500, 'p1', false)
let p2 = fakeAjax(1500, 'p2')
let p3 = fakeAjax(800, 'p3', false)
let p4 = fakeAjax(300, 'p4')
Promise.allSettled([p1, p2, p3, p4])
.then(res => console.log(res))
/*
res 的值为
[
{status: "rejected", reason: "p1"},
{status: "fulfilled", value: "p2"},
{status: "rejected", reason: "p3"},
{status: "fulfilled", value: "p4"},
]
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# resolve
概念: 该方法直接创建一个成功Promise
语法:
Promise.resolve(10086).then(res => console.log(res)) // 10086
# reject
概念: 该方法直接创建一个失败Promise
语法:
Promise.reject(new Error('失败')).catch(error => console.log(error)) // "失败"
# Async函数
概念: async 是 ES7 才有的与异步操作有关的关键字,他会将异步操作用同步代码的形式表现出来
语法: 是一个使用async关键声明的函数。在函数内部配合await关键字将异步回调的代码改写成同步代码的格式
function demo () {
new Promise(function (resolve, reject) {
let num = Math.random()
if (num > 0.5) {
resolve(num) // 成功调用resolve方法
} else {
reject('失败了!') // 调用reject方法
}
})
.then(res => console.log('成功!' + res))
.catch(err => console.error(err) )
}
// 下面的代码等价于上面的代码
async function asyncDemo() {
try {
let res = await new Promise(function (resolve, reject) {
let num = Math.random()
if (num > 0.5) {
resolve(num) // 成功调用resolve方法
} else {
reject('失败了!') // 调用reject方法
}
})
console.log(res, 'async')
}
catch (err) {
console.log('Error:'+ err)
}
}
asyncDemo()
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
注意
1. async 函数的返回值,不是普通对象的返回值,而是Promise对象
async function test() {
return 'hello world'
}
// test() 等价于 new Promise((resolve) => resolve('hello world'))
console.log(test()) // Promise {<resolved>: "hello world"}
test().then(r => console.log(r)) // 'hello world'
2
3
4
5
6
7
8
案例 axios的使用(Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中)
<!--引入axios三方库-->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
// 异步函数
async function test() {
let res = await axios('http://musicapi.leanapp.cn/search?keywords=一')
console.log(res)
}
// 普通函数
function test() {
axios('http://musicapi.leanapp.cn/search?keywords=二')
.then(res => {
console.log(res,'12313')
})
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
练习 使用Promise封装ajax
的get方法
function httpGet(url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
// 成功
let res = JSON.parse(xhr.responseText)
resolve(res)
} else {
// 失败
reject(new Error('失败'))
}
}
}
xhr.open("GET", url, true);
xhr.send();
})
}
httpGet('http://musicapi.leanapp.cn/search?keywords=换')
.then(res => console.log(res))
.catch(err => console.log(err))
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25