本文主要讨论一下Promise概念以及一些使用场景和如何正确使用。本文讨论的内容大概是适合对Promise的初学者,若是你已经对Promise很熟悉了,那么没有必要看。
面试
这两天参加了一个线上作题面试,有一道Promise的题目,颇有意思。作题的过程当中让我对Promise又有了新的理解。markdown
Prosmise这东西本质上就是一个设计的对象,根本没有什么神秘的。Promise就像一个飞去来器,扔出去,会有两种结果:
(1)成功的飞回手上
(2)飞的时候忽然爆炸了,渣都没了,只听到一声响:“reject!”
如今咱们直接看一个代码:async
// boomerang 是一个Promise 函数,你不用关心它如何实现的
// 你能够假设它是一个平时你能用到的HTTP call 能够返回特定的内容
// 它回成功返回数据(resolve),也可能失败(reject)
const boomerang = (s = 0, type = 'resolve', data = `飞去来器${s}型号回来了`) => {
if (type !== 'resolve') {
return new Promise((resolve, reject) =>
setTimeout(() => {
reject(new Error(`${s}毫秒后爆炸`));
}, s)
);
}
return new Promise((resolve) =>
setTimeout(() => {
resolve(data);
}, s)
);
};
const world = () => {
console.log('吃大葱');
const a = boomerang(0);
console.log(a);
const b = boomerang(1000, 'reject').catch((e) => {
return e.toString();
});
console.log(b);
const c = boomerang(2000);
console.log(c);
console.log('吃大蒜');
};
world();
复制代码
那么这段代码返回什么呢?如Prosmise不是特别熟悉,你可能会想错了。你可能会误觉得会返回’吃大葱‘
和’ 吃大蒜‘
而后后面跟着其它值是undefinied
;其实不是,下面看一下返回值:函数
吃大葱
Promise { <pending> }
Promise { <pending> }
Promise { <pending> }
吃大蒜
复制代码
Promise不是不会当即执行的吗?怎么没有返回值呢?Promise { <pending> }
是什么东西?
下面咱们先把Promise的基础再看一遍。Promise在JS任务队列里面是当即执行的。好比boomerang(0)
这个函数,是直接排在吃大葱后面的。只是Promise的返回值是在将来返回的,若是你像这个代码同样想得到boomerang函数返回值是不行的,你只能获得return new Promise
返回的结果,一个正在等待的Promise。 那么如何才能让这个代码正常工做呢?(获得a,b,c的值) 咱们能够用老派的then函数一顿then()而后进行处理(不推荐,代码落后于时代并且太难看也容易出bug)。下面咱们用标准的async/await重写一下:’优化
const world = async () => {
console.log('吃大葱');
const a = await boomerang(0);
console.log(a);
const b = await boomerang(1000, 'reject').catch((e) => {
return e.toString();
});
console.log(b);
const c = await boomerang(2000);
console.log(c);
console.log('吃大蒜');
};
world();
复制代码
这样返回结果就对了。ui
吃大葱
飞去来器0型号回来了
Error: 1000毫秒后爆炸
飞去来器2000型号回来了
吃大蒜
复制代码
这样的到了咱们想要的结果,并且咱们也对reject的函数正确地catch了错误。可是这个代码虽然能够正确执行,实际上仍是有一些问题的。问题在于,b的值须要等1秒,c的值须要等2秒,整个world()执行用了3秒。spa
这里面有3个Promise,实际上是能够同步执行的。下面咱们就要引出Promise.all
来对它们进行同步执行。改写代码以下:设计
const world = async () => {
console.time('test');
console.log('吃大葱');
const [a, b, c] = await Promise.all([
boomerang(0),
boomerang(1000, 'reject').catch((e) => {
return e.toString();
}),
boomerang(2000),
]);
console.log(a, b, c);
console.log('吃大蒜');
console.timeEnd('test');
};
world();
复制代码
看一下执行结果:code
吃大葱
飞去来器0型号回来了 Error: 1000毫秒后爆炸 飞去来器2000型号回来了
吃大蒜
test: 2005.940ms
复制代码
因此在实际工做的代码中,若是有多个Promise不是互相依赖的,要善用Promise.all
来进行优化。你可能对于代码中没有catchPromise.all
进行catch的错误抱有疑虑。其实在这里若是咱们对a,b,c的函数调用都进行了catch,就没必要对Promise.all
进行catch。这里须要加深理解。orm
暂时先写到这里。可能还须要写一下race什么的。