配色: 字号:
JavaScript Promise 的真正工作原理
2023-09-12 | 阅:  转:  |  分享 
  
?Promise 是处理异步代码的一种技术,也称为脱离回调地狱的头等舱门票。?编辑3 承诺状态待定状态已解决状态拒绝状态理解 JavaScr
ipt Promis什么是承诺?通常,承诺被定义为最终可用的值的代理。Promise 多年来一直是 JavaScript 的一部分
(在 ES2015 中标准化并引入)。最近,async和await关键字(在 ES2017 中引入)更深入地集成和清理了 Java
Script 中 Promise 的语法。异步函数在幕后使用 Promise,因此 - 特别是随着当今的分布式云架构变得越来越普遍
- 了解 Promise 是什么以及它们如何工作比以往任何时候都更加重要!现在我们知道承诺很重要,让我们深入探讨一下。Promi
se 如何发挥作用(简要说明)你的代码调用了一个承诺。该承诺将以所谓的待处理状态开始。这是什么意思?这意味着调用函数将在 Prom
ise 挂起时继续执行。一旦承诺得到解决,调用函数将获取承诺所请求的数据。Promise 开始于待处理状态,最终以已解决状态或拒绝
状态结束。无论最终结果是处于已解决状态的承诺还是处于拒绝状态的承诺,都将调用回调。我们定义两个单独的回调。当 Promise 以已
解决状态结束时,一个回调会处理从 Promise 返回的数据。当 Promise 以拒绝状态结束时,另一个回调处理 Promise
返回的数据。我们通过将回调函数传递给then 来定义处理以已解决状态结束的 Promise 数据的回调函数。我们通过将回调函数传
递给catch来定义处理以拒绝状态结束的 Promise 数据的回调函数。使用 axios npm 库的示例axios.get(e
ndpoint) .then(data => resolvedPromiseCallbackFunction(data)) .ca
tch(errors => rejectedPromiseCallbackFunction(errors))哪些 JavaScri
pt API 使用 Promise?您自己的代码和库很可能自始至终都使用 Promise。值得注意的是,Promise 实际上是由
标准现代 Web APIS 使用的。这里有几个也使用 Promise 的 Web API。https://developer.mo
zilla.org/en-US/docs/Web/API/Service_Worker_API服务工作者 APIhttps://d
eveloper.mozilla.org/en-US/docs/Web/API/Fetch_API获取API在现代 JavaScr
ipt 中,您不太可能发现自己处于不使用 Promise 的情况 - 所以让我们深入研究并开始理解它们。创造承诺JavaScrip
t 有一个 Promise API。Promise API 公开了一个 Promise 构造函数,您可以使用以下方法对其进行初始化
new Promise():let complete = trueconst hasItCompleted = new Promi
se((resolve, reject) => { if (complete) { ?const completed = ''Her
e is the thing I built''?resolve(completed) } else { const withRea
son = ''Still doing something else'' reject(withReason) }})如图所示,我们检
查complete全局常量。如果complete为 true,则 Promise 切换到已解决状态(也称为解析回调,它将 Prom
ise 切换到已解决状态)。否则,如果complete为 false,则reject执行回调,将 Promise 置于拒绝状态。好
吧 - 很简单,如果我们调用回调resolve,那么我们的 Promise 就会切换到已解决状态,就像我们使用reject回调一样
,我们的 Promise 会切换到拒绝状态。但这给我们留下了一个问题。如果我们既不调用resolve也不调用reject回调怎么办
?好吧,正如您可能正在组合的那样,承诺仍处于待处理状态。很简单,三个状态 - 两个回调函数切换到Resolved State或Re
jected State,如果我们都不调用回调,那么我们只是保持在Pending State。有前途您可能遇到的一个更常见的例子是
一种称为Promisifying 的技术。Promisifying是一种能够使用接受回调的经典 JavaScript 函数并让它返
回一个 Promise 的方法:const fileSystem = require(''fs'')const getFile = f
ile => {?return new Promise((resolve, reject) => {?fileSystem.rea
dFile(file, (err, data) => { if (err) { reject(err) return } ?
resolve(data)?})?})}let file = ''/etc/passwd''getFile(file)?.then(d
ata => console.log(data))?.catch(err => console.error(err))在 Node
.js 的最新版本中,您无需对许多 API 进行手动转换。util 模块中有一个promisifying 函数可以为您执行此操作,
前提是您所 promisifying 的函数具有正确的签名。消费承诺new Promise()现在了解了如何使用Promisify
ing技术创建 Promise?,让我们来谈谈使用Promise。我们如何使用承诺(又名我们如何使用承诺)const isItDo
neYet = new Promise(/ ... as above ... /)//...const checkIfItsD
one = () => {?isItDoneYet?.then(ok => {?console.log(ok)?})?.catch
(err => {?console.error(err)?})}运行将指定当承诺解决(在调用中)或拒绝(在调用中)checkIfI
tsDone()时要执行的函数。isItDoneYetthencatch流畅地链接 Promise如果我们想在前一个 Promis
e 返回后直接调用另一个 Promise 该怎么办?我们可以做到这一点,这简单地称为创建承诺链。链式 Promise 的示例可以在
Fetch API 中找到,它可用于获取资源并在获取资源时对要执行的 Promise 链进行排队(先进先出行)。首先,我们首先指
出Fetch API是一种基于承诺的机制。调用该fetch()方法相当于使用 定义我们自己的 Promise?new Promis
e()。下面是一个将 Promise 流畅地链接在一起的示例:const status = response => respon
se.status >= 200 && response.status < 300?? Promise.resolve(respo
nse)?: Promise.reject(new Error(response.statusText))const json =
response => response.json()fetch(''/items.json'').then(status).the
n(json).then(data => console.log(''Request success (with json): '',
data)).catch(error => console.log(''Request failed: '', error) “?h
ttps://www.npmjs.com/package/node-fetchnode-fetch是 Node.js 运行时上 w
indow.fetch 兼容 API 的最少代码。”那么,我们刚刚做了什么?好吧,在上面的示例中,我们调用从域根中找到的文件fet
ch()中获取项目列表。items.json然后我们创建一个承诺链。运行fetch()会返回https://fetch.spec.
whatwg.org/响应。响应包含status(数字 HTTP 状态代码)响应包含statusText(字符串消息,如果OK一切
成功)response还包含一个可调用的方法json()。Responses json 方法返回一个承诺,该承诺将通过处理并转换为
JSON.然后我们的链中有一个最终的 Promise 作为匿名回调函数传入。data => console.log(''Reques
t success (with json): '', data)这个函数只是记录我们成功了,并且控制台记录了成功的请求 json 数
据。_“如果第一个承诺被拒绝了怎么办?”如果第一个 Promise 被拒绝,或者第二个 Promise,或者第三个 Promise
- 那么,无论步骤如何,我们都会自动默认为catch直观地显示在我们流畅的 Promise 链末尾的回调方法。处理错误我们有一个
承诺链,有些东西失败了,呃哦 - 那么会发生什么?如果 Promise 链中的任何内容失败并引发错误或最终将 Promise 的状
态设置为Rejected Promise Statecatch()?,则控制将直接转到Promise 链中最近的语句。new Pr
omise((resolve, reject) => {?throw new Error(''Error'')}).catch(err
=> {?console.error(err)})// ornew Promise((resolve, reject) => {
?reject(''Error'')}).catch(err => {?console.error(err)})级联错误如果我们在a中
引发错误怎么办catch()?好吧,检查一下 - 我们可以简单地附加第二个catch().?第二个catch()将处理错误(或更具
体地说是错误消息)等等。new Promise((resolve, reject) => {?throw new Error(''E
rror'')})?.catch(err => {?throw new Error(''Error'')?})?.catch(err =
> {?console.error(err)?})承诺编排好的,现在我们对于单个 Promise 以及我们对 Promise 的基
本理解已经很扎实了。更进一步,让我们问另一个问题。如果您需要同步不同的 Promise - 比如说从多个端点提取数据并处理所有创建
并用于从这些不同端点检索结果的 Promise 中已解析的 Promise 数据 - 我们会怎么做?我们如何同步不同的 Promi
se 并在它们全部解决后执行某些操作?回答:?Promise.all()Promise.all()帮助我们定义一个承诺列表,并在它
们全部解决后执行某些操作 - 它允许我们同步承诺。Promise.all()?例子:const one = fetch(''/one
.json'')const two = fetch(''/two.json'')Promise.all([one, two])?.the
n(response => console.log(''Array of results: '', response)?.catch(
errors => console.error(errors))通过解构,我们可以将这个例子简化为:const [one, two
] = [fetch(''/one.json''), fetch(''/two.json'')]Promise.all([one, two
]).then(([resA, resB]) => console.log(''results: '', resA, resB))Pr
omise.race()如果我们想要从这些多个 API 获取所有数据,但实际上只需要从一个端点返回足够的数据来显示在我们的页面上,
该怎么办?也就是说,无论如何,我们都需要解决所有的 Promise,但是我们希望对第一个已解决的 Promise 中的数据执行某些
操作,并且我们不关心哪个 Promise 首先得到解决。为了处理第一个已解决的 Promise 中的数据,我们可以使用Promis
e.race().Promise.race()当您传递给它的第一个 Promise 解析时运行,并且它仅运行一次附加的回调,并得到第一个 Promise 解析的结果。例子const first = new Promise((resolve, reject) => {?setTimeout(resolve, 500, ''first'')})const second = new Promise((resolve, reject) => {?setTimeout(resolve, 100, ''second'')})Promise.race([first, second]).then(result => {?console.log(result) // second})?
献花(0)
+1
(本文系云端筑梦师A...原创)