初学者应该看的JavaScript Promise 完整指南

这篇文章算是 JavaScript Promises 比较全面的教程,该文介绍了必要的方法,例如 thencatchfinally。 此外,还包括处理更复杂的情况,例如与Promise.all并行执行Promise,通过Promise.race 来处理请求超时的情况,Promise 链以及一些最佳实践和常见的陷阱。

1.JavaScript Promises


Promise 是一个允许我们处理异步操作的对象,它是 es5 早期回调的替代方法。

与回调相比,Promise 具有许多优点,例如:

  • 让异步代码更易于阅读。

  • 提供组合错误处理。

* 更好的流程控制,可以让异步并行或串行执行。

回调更容易形成深度嵌套的结构(也称为回调地狱)。 如下所示:

a(() => {

b(() => {

c(() => {

d(() => {

// and so on …

});

});

});

});

如果将这些函数转换为 Promise,则可以将它们链接起来以生成更可维护的代码。 像这样:

Promise.resolve()

.then(a)

.then(b)

.then©

.then(d)

.catch(console.error);

在上面的示例中,Promise 对象公开了.then.catch方法,我们稍后将探讨这些方法。

1.1 如何将现有的回调 API 转换为 Promise?


我们可以使用 Promise 构造函数将回调转换为 Promise。

Promise 构造函数接受一个回调,带有两个参数resolvereject

  • Resolve:是在异步操作完成时应调用的回调。

  • Reject:是发生错误时要调用的回调函数。

构造函数立即返回一个对象,即 Promise 实例。 当在 promise 实例中使用.then方法时,可以在Promise “完成” 时得到通知。 让我们来看一个例子。

Promise 仅仅只是回调?

并不是。承诺不仅仅是回调,但它们确实对.then.catch方法使用了异步回调。 Promise 是回调之上的抽象,我们可以链接多个异步操作并更优雅地处理错误。来看看它的实际效果。

Promise 反面模式(Promises 地狱)

a(() => {

b(() => {

c(() => {

d(() => {

// and so on …

});

});

});

});

不要将上面的回调转成下面的 Promise 形式:

a().then(() => {

return b().then(() => {

return c().then(() => {

return d().then(() =>{

// ⚠️ Please never ever do to this! ⚠️

});

});

});

});

上面的转成,也形成了 Promise 地狱,千万不要这么转。相反,下面这样做会好点:

a()

.then(b)

.then©

.then(d)

超时

你认为以下程序的输出的是什么?

const promise = new Promise((resolve, reject) => {

setTimeout(() => {

resolve(‘time is up ⏰’);

}, 1e3);

setTimeout(() => {

reject(‘Oops 🔥’);

}, 2e3);

});

promise

.then(console.log)

.catch(console.error);

是输出:

time is up ⏰

Oops! 🔥

还是输出:

time is up ⏰

是后者,因为当一个Promise resolved 后,它就不能再被rejected

一旦你调用一种方法(resolvereject),另一种方法就会失效,因为 promise 处于稳定状态。 让我们探索一个 promise 的所有不同状态。

1.2 Promise 状态


Promise 可以分为四个状态:

  • ⏳ Pending:初始状态,异步操作仍在进行中。

  • ✅ Fulfilled:操作成功,它调用.then回调,例如.then(onSuccess)

  • ⛔️ Rejected: 操作失败,它调用.catch.then的第二个参数(如果有)。 例如.catch(onError).then(..., onError)

  • 😵 Settled:这是 promise 的最终状态。promise 已经死亡了,没有别的办法可以解决或拒绝了。 .finally方法被调用。

1.3 Promise 实例方法


Promise API 公开了三个主要方法:thencatchfinally。 我们逐一配合事例探讨一下。

大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】

Promise then

then方法可以让异步操作成功或失败时得到通知。 它包含两个参数,一个用于成功执行,另一个则在发生错误时使用。

promise.then(onSuccess, onError);

你还可以使用catch来处理错误:

promise.then(onSuccess).catch(onError);

Promise 链

then 返回一个新的 Promise ,这样就可以将多个Promise 链接在一起。就像下面的例子一样:

Promise.resolve()

.then(() => console.log(‘then#1’))

.then(() => console.log(‘then#2’))

.then(() => console.log(‘then#3’));

Promise.resolve立即将Promise 视为成功。 因此,以下所有内容都将被调用。 输出将是

then#1

then#2

then#3

Promise catch

Promise .catch方法将函数作为参数处理错误。 如果没有出错,则永远不会调用catch方法。

假设我们有以下承诺:1秒后解析或拒绝并打印出它们的字母。

const a = () => new Promise((resolve) => setTimeout(() => { console.log(‘a’), resolve() }, 1e3));

const b = () => new Promise((resolve) => setTimeout(() => { console.log(‘b’), resolve() }, 1e3));

const c = () => new Promise((resolve, reject) => setTimeout(() => { console.log(‘c’), reject(‘Oops!’) }, 1e3));

const d = () => new Promise((resolve) => setTimeout(() => { console.log(‘d’), resolve() }, 1e3));

请注意,c使用reject('Oops!')模拟了拒绝。

Promise.resolve()

.then(a)

.then(b)

.then©

.then(d)

.catch(console.error)

输出如下:

在这种情况下,可以看到abc上的错误消息。

我们可以使用then函数的第二个参数来处理错误。 但是,请注意,catch将不再执行。

Promise.resolve()

.then(a)

.then(b)

.then©

.then(d, () => console.log(‘c errored out but no big deal’))

.catch(console.error)

由于我们正在处理 .then(..., onError)部分的错误,因此未调用catchd不会被调用。 如果要忽略错误并继续执行Promise链,可以在c上添加一个catch。 像这样:

Promise.resolve()

.then(a)

.then(b)

.then(() => c().catch(() => console.log(‘error ignored’)))

.then(d)

.catch(console.error)

当然,这种过早的捕获错误是不太好的,因为容易在调试过程中忽略一些潜在的问题。

Promise finally

finally方法只在 Promise 状态是 settled 时才会调用。

如果你希望一段代码即使出现错误始终都需要执行,那么可以在.catch之后使用.then

Promise.resolve()

.then(a)

.then(b)

.then©

.then(d)

.catch(console.error)

.then(() => console.log(‘always called’));

或者可以使用.finally关键字:

Promise.resolve()

.then(a)

.then(b)

.then©

.then(d)

.catch(console.error)

.finally(() => console.log(‘always called’));

1.4 Promise 类方法


我们可以直接使用 Promise 对象中四种静态方法。

  • Promise.all

  • Promise.reject

  • Promise.resolve

  • Promise.race

Promise.resolve 和 Promise.reject

这两个是帮助函数,可以让 Promise 立即解决或拒绝。可以传递一个参数,作为下次 .then 的接收:

Promise.resolve(‘Yay!!!’)

.then(console.log)

.catch(console.error)

上面会输出 Yay!!!

Promise.reject(‘Oops 🔥’)

.then(console.log)

.catch(console.error)

使用 Promise.all 并行执行多个 Promise

通常,Promise 是一个接一个地依次执行的,但是你也可以并行使用它们。

假设是从两个不同的api中轮询数据。如果它们不相关,我们可以使用Promise.all()同时触发这两个请求。

在此示例中,主要功能是将美元转换为欧元,我们有两个独立的 API 调用。 一种用于BTC/USD,另一种用于获得EUR/USD。 如你所料,两个 API 调用都可以并行调用。 但是,我们需要一种方法来知道何时同时完成最终价格的计算。 我们可以使用Promise.all,它通常在启动多个异步任务并发运行并为其结果创建承诺之后使用,以便人们可以等待所有任务完成。

const axios = require(‘axios’);

const bitcoinPromise = axios.get(‘https://api.coinpaprika.com/v1/coins/btc-bitcoin/markets’);

const dollarPromise = axios.get(‘https://api.exchangeratesapi.io/latest?base=USD’);

const currency = ‘EUR’;

// Get the price of bitcoins on

Promise.all([bitcoinPromise, dollarPromise])

.then(([bitcoinMarkets, dollarExchanges]) => {

const byCoinbaseBtc = d => d.exchange_id === ‘coinbase-pro’ && d.pair === ‘BTC/USD’;

const coinbaseBtc = bitcoinMarkets.data.find(byCoinbaseBtc)

const coinbaseBtcInUsd = coinbaseBtc.quotes.USD.price;

const rate = dollarExchanges.data.rates[currency];

return rate * coinbaseBtcInUsd;

})

.then(price => console.log(The Bitcoin in ${currency} is ${price.toLocaleString()}))

.catch(console.log);

如你所见,Promise.all接受了一系列的 Promises。 当两个请求的请求都完成后,我们就可以计算价格了。

我们再举一个例子:

const a = () => new Promise((resolve) => setTimeout(() => resolve(‘a’), 2000));

const b = () => new Promise((resolve) => setTimeout(() => resolve(‘b’), 1000));

const c = () => new Promise((resolve) => setTimeout(() => resolve(‘c’), 1000));

const d = () => new Promise((resolve) => setTimeout(() => resolve(‘d’), 1000));

console.time(‘promise.all’);

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

由于篇幅限制,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!有需要的程序猿(媛)可以帮忙点赞+点击【学习资料】即可免费领取!

工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-6AMNiWq4-1713696865984)]

[外链图片转存中…(img-k2rEK2ig-1713696865985)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-6KqjhBR8-1713696865985)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

[外链图片转存中…(img-62t6XABd-1713696865985)]

最后

由于篇幅限制,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!有需要的程序猿(媛)可以帮忙点赞+点击【学习资料】即可免费领取!

[外链图片转存中…(img-04NYI6LD-1713696865986)]

[外链图片转存中…(img-ta3oovUr-1713696865986)]

  • 17
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值