# 异步任务的处理
# 使用回调函数的方式请求
function requestData(url, resCallback, errCallback) {
setTimeout(() => {
if (url == "okarin") {
let res = "Hello World!"
resCallback(res)
} else {
let err = "Error"
errCallback(err)
}
},2000)
}
requestData(
"okarin",
(res) => {
console.log(res)
},
(err) => {
console.log(err)
}
)
requestData(
"retr0",
(res) => {
console.log(res)
},
(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
26
27
28
29
30
31
这种请求的弊端:
- 我们需要自己来设计回调函数、回调函数的名称、回调函数的使用等;
- 对于不同的人、不同的框架设计出来的方案是不同的,那么我们必须耐心去看别人的源码或者文档,以便可以理解它这个函数到底怎么用;
# 使用Promise的方式
我们来看一下Promise的API是怎么样的:
Promise是一个类,可以翻译成 承诺、许诺、期约;
当我们需要给予调用者一个承诺:待会儿我会给你回调数据时,就可以创建一个Promise的对象;
在通过new创建Promise对象时,我们需要传入一个回调函数,我们称之为executor
- 这个回调函数会被立即执行,并且给传入另外两个回调函数resolve、reject;
- 当我们调用resolve回调函数时,会执行Promise对象的then方法传入的回调函数;
- 当我们调用reject回调函数时,会执行Promise对象的catch方法传入的回调函数;
function requestData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url == "okarin") {
let res = "Hello World!"
resolve(res)
} else {
let err = "Error"
reject(err)
}
}, 2000)
})
}
requestData("okarin")
.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
# Promise的代码结构
new Promise((resolve, reject) => {
setTimeout(() => {
//pending
resolve("succeed") //成功的时候调用
reject("error") //失败的时候调用
}, 1000)
})
.then((resolve) => {
//fulfilled
//成功之后执行
console.log(resolve)
})
.catch((err) => {
//rejected
//失败之后执行
console.log(err)
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Promise 三种状态
- pending: 等待状态,比如正在进行网络请求,或者定时器没有到时间
- fulfill: 满足状态,当主动回调resolve时,就处于该状态,并且会回调.then()
- reject: 拒绝状态,当主动回调reject时,就处于该状态,并且会回调.catch()
注意:状态一旦确定,就不能更改。
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("succeed")
console.log("状态确定")
reject("error")
}, 1000)
})
.then((resolve) => {
console.log(resolve)
})
.catch((err) => {
console.log(err)
})
//succeed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Promise参数
resolve不同值的区别
- 如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数;
- 如果resolve中传入的是另外一个Promise,那么这个新Promise会决定原Promise的状态:
- 如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,并且根据then方法的结果来决定Promise的状态:
const newPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("success")
}, 1000)
})
new Promise((resolve, reject) => {
setTimeout(() => {
//传入一个新的Promise
resolve(newPromise) //成功的时候调用
}, 1000)
})
.then((resolve) => {
//成功之后执行
console.log("success:" + resolve)
})
.catch((err) => {
//失败之后执行
console.log(err)
})
//success:success
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const obj = {
then:function(resolve,reject){
resolve("thenable")
}
}
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(obj) //成功的时候调用
}, 1000)
})
.then((resolve) => {
//成功之后执行
console.log("success:" + resolve)
})
.catch((err) => {
//失败之后执行
console.log(err)
})
//success:thenable
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Promise 实例方法
Promise的实例方法,是存放在Promise的prototype上的方法。
const promise = new Promise((resolve, reject) => {
resolve()
// reject(err)
})
promise.then(()=>{
console.log("resolve")
})
promise.catch(()=>{
console.log("reject")
})
promise.finally(()=>{
console.log("finally code ")
})
2
3
4
5
6
7
8
9
10
11
12
13
14
我们可以获取一下原型上的方法
console.log(Object.getOwnPropertyDescriptors(Promise.prototype))
结果
// {
// constructor: {
// value: [Function: Promise],
// writable: true,
// enumerable: false,
// configurable: true
// },
// then: {
// value: [Function: then],
// writable: true,
// enumerable: false,
// configurable: true
// },
// catch: {
// value: [Function: catch],
// writable: true,
// enumerable: false,
// configurable: true
// },
// finally: {
// value: [Function: finally],
// writable: true,
// enumerable: false,
// configurable: true
// },
// value: 'Promise',
// writable: false,
// enumerable: false,
// configurable: true
// }
// }
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
# then 方法
then方法是Promise对象上的一个方法:它其实是放在Promise的原型上的Promise.prototype.then
,then 方法接受两个参数:
- fulfilled的回调函数:当状态变成fulfilled时会回调的函数;
- reject的回调函数:当状态变成reject时会回调的函数;
function requestData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url == "okarin") {
let res = "Hello World!"
resolve(res)
} else {
let err = "Error"
reject(err)
}
}, 2000)
})
}
requestData().then(
(res) => {
console.log("succeed:" + res)
},
(err) => {
//失败之后执行
console.log("Error:" + err)
}
)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
一个Promise的then方法是可以被多次调用的:
- 每次调用我们都可以传入对应的fulfilled回调;
- 当Promise的状态变成fulfilled的时候,这些回调函数都会被执行;
promise.then((res) => {
console.log("res1:" + res)
})
promise.then((res) => {
console.log("res2:" + res)
})
promise.then((res) => {
console.log("res3:" + res)
})
2
3
4
5
6
7
8
9
then方法本身是有返回值的,它的返回值是一个Promise,所以我们可以进行如下的链式调用:
- 但是then方法返回的Promise到底处于什么样的状态呢?
Promise有三种状态,那么这个Promise处于什么状态呢?
当then方法中的回调函数本身在执行的时候,那么它处于pending状态;
当then方法中的回调函数返回一个结果时,那么它处于fulfilled状态,并且会将结果作为resolve的参数;
情况一:返回一个普通的值;
情况二:返回一个Promise;
情况三:返回一个thenable值;
当then方法抛出一个异常时,那么它处于reject状态;
# catch方法
catch方法也是Promise对象上的一个方法:
它也是放在Promise的原型上的 Promise.prototype.catch
一个Promise的catch方法是可以被多次调用的:
- 每次调用我们都可以传入对应的reject回调;
- 当Promise的状态变成reject的时候,这些回调函数都会被执行;
function requestData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url == "okarin") {
let res = "Hello World!"
resolve(res)
} else {
let err = "Error"
reject(err)
}
}, 2000)
})
}
requestData().catch((err) => {
//失败之后执行
console.log("catch1:" + err)
})
requestData().catch((err) => {
//失败之后执行
console.log("catch2:" + err)
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# catch方法的返回值
catch方法也是会返回一个Promise对象,所以catch方法后面我们可以继续调用then方法或者catch方法:
function requestData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url == "okarin") {
let res = "Hello World!"
resolve(res)
} else {
let err = "Error"
reject(err)
}
}, 2000)
})
}
requestData()
.catch((err) => {
//失败之后执行
console.log("catch:" + err)
return "catch return value"
})//继续调用then方法和catch方法
.then((res) => {
console.log("succeed:" + res)
})
.catch((err) => {
//失败之后执行
console.log("catch2:" + err)
})
//catch:Error
//succeed:catch return value
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
在上面的代码中,在catch后面继续调用then方法和catch方法。回调的是then方法。
这是因为 catch 传入的回调在执行完后,默认状态依然会是fulfilled的;相当于
new Promise(resolve => resolve(x))
要继续调用catch,就需要继续抛出异常
requestData()
.catch((err) => {
//失败之后执行
console.log("catch:" + err)
return new Promise((resolve, reject) => {
reject(err)
})
})
.then((res) => {
console.log("succeed:" + res)
})
.catch((err) => {
//失败之后执行
console.log("catch2:" + err)
})
//catch:Error
//catch2:Error
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# finally方法 ES9新增
finally是在 ES9(ES2018)中新增的一个特性:表示无论Promise对象无论变成 fulfilled 还是 rejected 状态,最终都会被执行的代码。
finally方法是不接收参数的,因为无论前面是fulfilled状态,还是rejected状态,它都会执行。
function requestData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url == "okarin") {
let res = "Hello World!"
resolve(res)
} else {
let err = "Error"
reject(err)
}
}, 2000)
})
}
requestData("okarin")
.then((res) => {
console.log("succeed:" + res)
})
.catch((err) => {
//失败之后执行
console.log("catch:" + err)
}).finally(()=>{
console.log("finally code ")
})
//succeed:Hello World!
//finally code
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
# Promise类方法
# resolve方法
有时候我们已经有一个现成的内容了,希望将其转成Promise来使用
function foo(){
const obj = {name:"okarin"}
return new Promise((resolve)=>{
resolve(obj)
})
}
foo().then(res =>{
console.log("res:",res)
})
2
3
4
5
6
7
8
9
10
这个时候我们可以使用 Promise.resolve
方法来完成。Promise.resolve
的用法相当于new Promise,并且执行resolve操作:
function foo(){
const obj = {name:"okarin"}
return Promise.resolve(obj)
}
foo().then(res =>{
console.log("res:",res)
})
2
3
4
5
6
7
8
9
同时,当resolve传入的是 promise 或者 thenable 时,会根据promise和thenable来回调。
const newPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("success")
}, 1000)
})
function foo() {
const obj = { name: "okarin" }
return Promise.resolve(newPromise)
}
foo()
.then((res) => {
console.log("res:", res)
})
.catch((err) => {
console.log("err:", err)
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# reject方法
function foo() {
const obj = { name: "okarin" }
return Promise.reject(obj)
}
foo()
.then((res) => {
console.log("res:", res)
})
.catch((err) => {
console.log("err:", err)
})
2
3
4
5
6
7
8
9
10
11
12
13
注意:无论reject传入什么值,都是一样的。
传入一个Promise
const newPromise = new Promise((resolve, reject) => {
setTimeout(() => {
reject("Error")
}, 1000)
})
function foo() {
const obj = { name: "okarin" }
return Promise.reject(newPromise)
}
foo()
.then((res) => {
console.log("res:", res)
})
.catch((err) => {
console.log("err:", err)
})
//err: Promise { <pending> }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
传入一个Function
const newPromise = function(resolve, reject){
setTimeout(() => {
reject("Error")
}, 1000)
}
function foo() {
const obj = { name: "okarin" }
return Promise.reject(newPromise)
}
foo()
.then((res) => {
console.log("res:", res)
})
.catch((err) => {
console.log("err:", err)
})
//err: [Function: newPromise]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# all方法
在所有的Promise都变成fulfilled时,再拿到结果
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("okarin")
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(18)
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("chengdu")
}, 3000)
})
const message = "Hello World!"
Promise.all([p1, p2, p3, message]).then((res) => {
console.log(res)
}).catch(err => {
console.log(err)
})
//[ 'okarin', 18, 'chengdu', 'Hello World!' ]
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
注意:当其中一个Promise变成 rejected状态时,新的Promise就会立即变成对应的reject状态。而对于resolved,以及依然处于pending状态的Promise,则获取不到对应的结果。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("okarin")
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("ERROR") //ERROR
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("SECEND ERROR")//ERROR 拿不到第二次错误
}, 3000)
})
const message = "Hello World!"
Promise.all([p1, p2, p3, message]).then((res) => {
console.log(res)
}).catch(err => {
console.log(err)
})
//ERROR
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
# allSettled方法 ES11新增
为了解决all方法的缺陷,在ES11(ES2020)中,添加了新的API
Promise.allSettled
- 该方法会在所有的Promise都有结果(settled)时,无论是fulfilled,还是rejected时,才会有最终的状态。
- 这个Promise的结果一定是fulfilled的。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("okarin")
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("ERROR") //ERROR
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("SECEND ERROR")
}, 3000)
})
const message = "Hello World!"
Promise.allSettled([p1, p2, p3, message]).then((res) => {
console.log(res)
}).catch(err => {
console.log(err)
})
// [
// { status: 'fulfilled', value: 'okarin' },
// { status: 'rejected', reason: 'ERROR' },
// { status: 'rejected', reason: 'SECEND ERROR' },
// { status: 'fulfilled', value: 'Hello World!' }
// ]
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
### race方法
如果一个Promise有了结果,希望用这个结果来决定最终Promise的状态,那么就可以用race方法。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("okarin")
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("ERROR") //ERROR
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("SECEND ERROR")
}, 3000)
})
Promise.race([p1, p2, p3]).then((res) => {
console.log(res)
}).catch(err => {
console.log(err)
})
//okarin
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
注意:如果有一个Promise的状态先变成了rejected,那么新的Promise也会变成rejected状态。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("okarin")
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("ERROR") //ERROR
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("SECEND ERROR")
}, 500) //先触发
})
Promise.race([p1, p2, p3]).then((res) => {
console.log(res)
}).catch(err => {
console.log(err)
})
//SECEND ERROR
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
# any方法 ES12新增
any方法是ES12中新增的方法,和 race方法类似;
- any方法会等到一个fulfilled状态,才会决定新Promise的状态;
- 如果所有的Promise都是reject,那么也会等到所有的Promise变成rejected状态;
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("okarin")
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("ERROR") //ERROR
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("SECEND ERROR")
}, 3000)
})
Promise.any([p1, p2, p3]).then((res) => {
console.log(res)
}).catch(err => {
console.log(err)
})
//okarin
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
所有的Promise都是reject
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("FIRST ERROR")
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("SECEND ERROR")
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("THIRD ERROR")
}, 3000)
})
Promise.any([p1, p2, p3]).then((res) => {
console.log(res)
}).catch(err => {
console.log(err)
})
//AggregateError: All promises were rejected
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
# Promise的简单实现
const PROMISE_STASUS_PENDING = "pending"
const PROMISE_STASUS_FULFILLED = "fulfilled"
const PROMISE_STASUS_REJECTED = "rejected"
class onPromise {
constructor(excutor) {
this.status = PROMISE_STASUS_PENDING
const resolve = (value) => {
if (this.status === PROMISE_STASUS_PENDING) {
this.status = PROMISE_STASUS_FULFILLED
queueMicrotask(() => {
this.onFulfilled(value)
})
}
}
const reject = (reason) => {
if (this.status === PROMISE_STASUS_PENDING) {
this.status = PROMISE_STASUS_REJECTED
queueMicrotask(() => {
this.onRejected(reason)
})
}
}
excutor(resolve, reject)
}
then(onFulfilled, onRejected) {
this.onFulfilled = onFulfilled
this.onRejected = onRejected
}
}
const promise = new onPromise((resolve, reject) => {
resolve(1111)
// reject()
}).then((res) => {
console.log("res:" + res)
}, (err) => {
console.log("err:" + 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40