Table of Contents generated with DocToc (opens new window)
Promise对象:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
# Promise的状态
三种状态:
pending(进行中)fulfilled(已成功)rejected(已失败)
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。
// Promise实例
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
2
3
4
5
6
7
8
9
10
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。
resolve和reject是两个回调函数
# then-catch
then() 方法返回一个 Promise (opens new window)。它最多需要有两个参数:Promise 的成功和失败情况的回调函数。
then也可以捕获错误
p.then(onFulfilled[, onRejected]);
/*
onFulfilled 可选
当 Promise 变成接受状态(fulfilled)时调用的函数。该函数有一个参数,即接受的最终结果(the fulfillment value)。如果该参数不是函数,则会在内部被替换为 (x) => x,即原样返回 promise 最终结果的函数
onRejected 可选
当 Promise 变成拒绝状态(rejected)时调用的函数。该函数有一个参数,即拒绝的原因(rejection reason)。 如果该参数不是函数,则会在内部被替换为一个 "Thrower" 函数 (it throws an error it received as argument)。
*/
2
3
4
5
6
7
const pm1 = new Promise((resolve, reject) => {
resolve('success')
})
pm1.then(
(val) => {
console.log(val)
},
(err) => {
console.log(err)
}
)
2
3
4
5
6
7
8
9
10
11
12
p.catch(onRejected);
p.catch(function(reason) {
// 拒绝
});
2
3
4
5
catch实际上是then的语法糖,mdn关于catch的解释
catch() 方法返回一个Promise (opens new window),并且处理拒绝的情况。它的行为与调用
Promise.prototype.then(undefined, onRejected)(opens new window) 相同。 (事实上, callingobj.catch(onRejected)内部callsobj.then(undefined, onRejected)).
# then vs then catch
myPromise.then(function() {
// Some error may happen
throw('An exception that would be caught');
}).catch(function() {
console.log('error');
});
// Is the same as this, the errHandle tries to catch any unhandled error
// from previous result.
myPromise.then(func, null).then(null, errHandle);
myPromise.then(function() {
// Some error may happen
throw('An unhandled exception.');
}, function() {
// This won't log the error if it happens in the
// some error may happen block.
console.log('error');
});
// Is the same as this, the errHandle will handle errors from previous result,
// but it won't handle errs in func.
myPromise.then(func, errHandle)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**一般总是建议,Promise 对象后面要跟catch()方法,这样可以处理 Promise 内部发生的错误。**catch()方法返回的还是一个 Promise 对象,因此后面还可以接着调用then()方法。
const someAsyncThing = function() {
return new Promise(function(resolve, reject) {
// 下面一行会报错,因为x没有声明
resolve(x + 2);
});
};
someAsyncThing()
.catch(function(error) {
console.log('oh no', error);
})
.then(function() {
console.log('carry on');
});
// oh no [ReferenceError: x is not defined]
// carry on
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
上面代码运行完catch()方法指定的回调函数,会接着运行后面那个then()方法指定的回调函数。如果没有报错,则会跳过catch()方法。
# 使用Promise进行错误处理
使用 promise 进行错误处理 (opens new window)
new Promise((resolve, reject) => {
throw new Error("Whoops!");
}).catch(alert); // Error: Whoops!
2
3
……与下面这段代码工作上完全相同:
new Promise((resolve, reject) => {
reject(new Error("Whoops!"));
}).catch(alert); // Error: Whoops!
2
3
# Promise的学习
var p = new Promise(function (resolve, reject) {
//做一些异步操作
setTimeout(function () {
console.log('执行完成')
resolve('随便什么数据')
}, 2000)
})
p.then((res) => console.log(res)).catch((err) => console.log(err))
// then方法接收一个参数,是函数,并且会拿到我们在p中调用resolve时传的参数。
// 运行这段代码,会在2秒后输出"执行完成",紧接着输出"随便什么数据"。
2
3
4
5
6
7
8
9
10
11
# 链式操作+递归
function runAsync(param) {
return new Promise(function (resolve, reject) {
//做一些异步操作
setTimeout(function () {
console.log('执行完成')
resolve(param)
}, 500)
})
}
runAsync(1)
.then((res) => {
console.log(1)
return runAsync(2)
})
.then((res) => {
console.log(res)
return runAsync(3)
})
.then((res) => console.log(res))
/* 执行完成
1
执行完成
2
执行完成
3 */
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的Api
# Promise.all
等待所有 Promise 完成,并返回所有结果。如果有一个 Promise 失败,则返回失败的结果。
Promise.allSettled:等待所有 Promise 完成,无论成功还是失败,返回每个 Promise 的结果。
Promise.race:等待第一个完成的 Promise 并返回其结果(无论成功还是失败)。
Promise.any:返回第一个成功的Promise结果,如果全部失败,则返回AggregateError对象。
- 功能:
Promise.all用于接收一个包含多个 Promise 的可迭代对象,并在所有 Promise 都成功解决时才会解决,如果其中任何一个 Promise 被拒绝(rejected),则返回的 Promise 会立即被拒绝,并以第一个被拒绝的 Promise 的错误作为拒绝原因。 - 行为: 返回的 Promise 解析为一个包含所有 Promise 解析值的数组,该数组的顺序与传入的 Promise 的顺序相同。
- 适用场景: 当需要同时等待多个异步操作都成功完成后再执行下一步操作时,通常会使用
Promise.all。
function makePromise(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(time);
}, time);
});
}
Promise.all([makePromise(2000), makePromise(3000), makePromise(4000)]).then(
(res) => {
console.log(res);
}
);
//[ 2000, 3000, 4000 ]
//exited with code=0 in 5.054 seconds
// 在所有Promise的状态都凝固后再执行then
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Promise.allSettled
- 功能:
Promise.allSettled用于接收一个包含多个 Promise 的可迭代对象,并在所有 Promise 都被解决后返回一个 Promise,该 Promise 总是解决,不管每个 Promise 的状态是解决还是被拒绝。 - 行为: 返回的 Promise 解析为一个包含所有 Promise 解决状态的数组,每个数组元素都包含一个对象,该对象表示对应的 Promise 的状态和结果(如果有)。
- 适用场景: 当需要等待多个异步操作都完成后,无论成功或失败,都执行下一步操作时,通常会使用
Promise.allSettled。
Promise.allSettled([pm2, pm1, pm2, makePromise(5000)])
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
/*
[
{ status: 'fulfilled', value: 'error' },
{ status: 'fulfilled', value: 2000 },
{ status: 'fulfilled', value: 'error' },
{ status: 'fulfilled', value: 5000 }
]
*/
// exited with code=0 in 5.054 seconds
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
当您有多个彼此不依赖的异步任务成功完成时,或者您总是想知道每个promise的结果时,通常使用它。
相比之下,Promise.all() 更适合彼此相互依赖或者在其中任何一个reject时立即结束。
# Promise 防止阻塞
promise防止阻塞
function timeoutPromise(interval) {
return new Promise((resolve, reject) => {
setTimeout(function () {
console.log('done')
resolve('done')
}, interval)
})
}
function timeTest() {
// return timeoutPromise(2000)
// .then(() => timeoutPromise(3000))
// .then(() => timeoutPromise(4000))
// 防止阻塞 赋值的本质 是因为Promise实例一旦建立就会立即执行,而后面的then是为了获取Promise实例的状态
const timeout1 = timeoutPromise(2000)
const timeout2 = timeoutPromise(3000)
const timeout3 = timeoutPromise(4000)
return timeout1.then(() => timeout2).then(() => timeout3)
}
let startTime = Date.now()
timeTest().then(() => {
let finishTime = Date.now()
let timeTaken = finishTime - startTime
console.log('Time taken in milliseconds: ' + timeTaken)
})
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防止阻塞
1.Promise存储到变量中可以防止阻塞
const ajax = (time: number) =>
new Promise((resolve) => {
setTimeout(() => {
console.log(time);
resolve(time);
}, time);
});
const start2 = async () => {
console.time("test");
const timeout1 = ajax(2000);
const timeout2 = ajax(3000);
const timeout3 = ajax(4000);
await timeout1;
await timeout2;
await timeout3;
console.timeEnd("test");
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
赋值的本质 是因为Promise实例一旦建立就会立即执行,而后面的then是为了获取Promise实例的状态
2.Promise.all
const start = async () => {
console.time("test");
await Promise.all([ajax(2000), ajax(3000), ajax(4000)]);
console.timeEnd("test");
};
2
3
4
5
# Promise的执行顺序
Mdn:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises
# 时序
为了避免意外,即使是一个已经变成 resolve 状态的 Promise,传递给 then() 的函数也总是会被异步调用:
Promise.resolve().then(() => console.log(2));
console.log(1); // 1, 2
2
传递到 then() 中的函数被置入到一个微任务队列中,而不是立即执行,这意味着它是在 JavaScript 事件队列的所有运行时结束了,且事件队列被清空之后,才开始执行:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
wait().then(() => console.log(4));
Promise.resolve().then(() => console.log(2)).then(() => console.log(3));
console.log(1); // 1, 2, 3, 4
2
3
4
5
# Async await reject问题
async await语法不能接收reject,需要使用try catch处理
# Promise并行
先来看几段代码
代码一:
const getLoader = async () => {
const numberVal = await route.meta.number
const nameVal = await route.meta.name
number.value = numberVal
name.value = nameVal
}
2
3
4
5
6
- 串行执行:两个
await是依次执行的,先等待一个Promise,再等待另一个。
代码二:
const getLoader = async () => {
const numberVal = route.meta.number
const nameVal = route.meta.name
number.value = await numberVal
name.value = await nameVal
}
2
3
4
5
6
两个 Promise 可以并行执行