美好的一天,哈伯! 我向您介绍Sukhjinder Arora撰写的文章
“ JavaScript中的理解承诺” 。
翻译作者:以及作者本人,我希望这篇文章对您有所帮助。 拜托,如果她真的帮助您自己学习了一些新知识,那么不要太懒惰,不去阅读原始文章并感谢作者! 我很高兴收到您的反馈!
链接到同一作者在异步JavaScript上的文章翻译 。JavaScript是一种单线程编程语言,这意味着一次可以完成一件事情。 在ES6之前,我们使用回调来管理异步任务,例如网络请求。
使用promise,我们可以避免“ hell回调”,并使我们的代码更简洁,更具可读性且更易于理解。
假设我们想异步地从服务器获取一些数据,使用回调,我们将执行以下操作:
getData(function(x){ console.log(x); getMoreData(x, function(y){ console.log(y); getSomeMoreData(y, function(z){ console.log(z); }); }); });
在这里,我使用
getData()函数从服务器请求一些数据,该函数在回调函数内部接收数据。 在回调函数中,我通过调用
getMoreData()函数,将先前的数据作为参数传递
等等来请求其他数据。
这就是我们所说的“回调地狱”,其中每个回调嵌套在另一个回调中,并且每个内部回调都取决于其父级。
我们可以使用promise重写上面的代码片段:
getData() .then((x) => { console.log(x); return getMoreData(x); }) .then((y) => { console.log(y); return getSomeMoreData(y); }) .then((z) => { console.log(z); });
您可以看到比第一个回调示例更具可读性的内容。
什么是诺言?
Promise(承诺)是一个包含异步操作的将来值的对象。 例如,如果您从服务器请求一些数据,Promis承诺我们将接收这些数据,以备将来使用。
在深入探讨所有这些技术内容之前,让我们看一下诺言的术语。
承诺状态
JavaScript中的承诺与现实生活中的承诺一样,具有3个状态。 可以是1)未解决(待处理),2)已解决/已解决(已完成)或3)被拒绝/被拒绝。
未解决或待处理 -如果结果未准备好,Promis将等待。 也就是说,它期望某些事情完成(例如,异步操作的完成)。
已解决或已完成 -如果结果可用,则承诺已解决。 也就是说,某些东西完成了其执行(例如,异步操作),并且一切顺利。
已拒绝 -如果执行期间发生错误,则Promis会被拒绝。
现在我们知道Promis及其术语是什么,让我们回到Promise的实际部分。
创建承诺
在大多数情况下,您只会使用承诺而不是创建承诺,但是了解如何创建它们很重要。
语法:
const promise = new Promise((resolve, reject) => { ... });
我们使用Promises构造函数创建了一个新的promise,它接受一个参数,即回调,也称为执行函数,它接受2个回调,
resolve和
reject 。
创建承诺后,立即执行执行功能。 通过调用
resolve()做出承诺,并由
reject()拒绝 。 例如:
const promise = new Promise((resolve, reject) => { if(allWentWell) { resolve(' !'); } else { reject('- '); } });
resolve()和
reject()采用一个参数,该参数可以是字符串,数字,逻辑表达式,数组或对象。
让我们看另一个示例,以充分理解如何创建承诺。
const promise = new Promise((resolve, reject) => { const randomNumber = Math.random(); setTimeout(() => { if(randomNumber < .6) { resolve(' !'); } else { reject('- '); } }, 2000); });
在这里,我使用Promis构造函数创建了一个新的Promise。 创建承诺后2秒钟执行或拒绝承诺。 如果
randomNumber小于.6,则执行诺言,在其他情况下,则拒绝。
创建承诺后,它将处于待处理状态,并且其值将是
undefined 。
2秒后,计时器结束,promise将随机执行或拒绝,其值将是传递给
resolve或
reject函数的值。 下面是两种情况的示例:
成功完成:

承诺拒绝:
注意:承诺只能执行一次或拒绝一次。 进一步调用
solve()或
reject()不会以任何方式影响promise的状态。 一个例子:
const promise = new Promise((resolve, reject) => { resolve('Promise resolved');
由于首先调用了
resolve() ,所以Promise现在的状态为“已完成”。 后续对
reject()的调用不会以任何方式影响promise的状态。
使用承诺
现在我们知道了如何创建承诺,现在让我们弄清楚如何应用已经创建的承诺。 我们使用
then()和
catch()方法使用promise。
例如,使用
fetch从API查询数据,这将返回一个promise。
.then() 语法: promise.then(successCallback,failureCallback)如果promise已成功执行,则调用
successCallback 。 它采用一个参数,该参数是传递给
resolve()的值。
如果承诺已被拒绝,则调用
failureCallback 。 它采用一个参数,这是指定给
reject()的值。
一个例子:
const promise = new Promise((resolve, reject) => { const randomNumber = Math.random(); if(randomNumber < .7) { resolve(' !'); } else { reject(new Error('- ')); } }); promise.then((data) => { console.log(data);
如果已执行诺言,则使用传递给
resolve()的值来
调用successCallback 。 并且如果诺言被拒绝,那么
将使用传递给reject()的值来
调用failureCallback 。
.catch() 语法: promise.catch (failureCallback)我们使用
catch()处理错误。 这比
then()方法回调内部的
failCallback内部的错误处理更具可读性。
const promise = new Promise((resolve, reject) => { reject(new Error('- ')); }); promise .then((data) => { console.log(data); }) .catch((error) => { console.log(error);
承诺链
then()和
catch()方法还可以返回一个新的promise,可以在上一个then()方法的末尾由一个其他then()链处理。
当我们要完成一系列承诺时,我们会使用一系列承诺。
例如:
const promise1 = new Promise((resolve, reject) => { resolve('Promise1 '); }); const promise2 = new Promise((resolve, reject) => { resolve('Promise2 '); }); const promise3 = new Promise((resolve, reject) => { reject('Promise3 '); }); promise1 .then((data) => { console.log(data);
那么这是怎么回事?
满足
promise1后 ,将调用
then()方法
,该方法返回promise2。
接下来,当
promise2满足时 ,
然后再次调用
()并返回
promise3 。
由于promise3被拒绝,因此而不是下一个
then() ,将调用
catch()来处理对
promise3的拒绝。
注意:通常,一个
catch()方法足以处理链中任何promise的拒绝(如果此方法位于末尾)。
常见错误
很多新来者通过将一些承诺投资于其他承诺中而犯错。 例如:
const promise1 = new Promise((resolve, reject) => { resolve('Promise1 '); }); const promise2 = new Promise((resolve, reject) => { resolve('Promise2 '); }); const promise3 = new Promise((resolve, reject) => { reject('Promise3 '); }); promise1.then((data) => { console.log(data);
尽管这可以很好地工作,但是它被认为是不好的样式,并且使代码的可读性降低。 如果您要执行一系列承诺,最好将它们一个接一个地放置,而不是一个放入另一个内。
Promise.all()
此方法接受一个promise数组,并返回一个新的promise,当找到或拒绝了一个promise时,将执行或拒绝数组中的所有promise时执行一个新的promise。 例如:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 2000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise2 '); }, 1500); }); Promise.all([promise1, promise2]) .then((data) => console.log(data[0], data[1])) .catch((error) => console.log(error));
在这里,
then()内的参数是一个数组,其中包含将promise的值传递到
Promise.all()的顺序(仅当所有promise被执行时)。
承诺被拒绝,原因是拒绝了已传输数组中的第一个承诺。 例如:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 2000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('Promise2 '); }, 1500); }); Promise.all([promise1, promise2]) .then((data) => console.log(data[0], data[1])) .catch((error) => console.log(error));
在这里,我们有两个承诺,其中一个在2秒后执行,另一个在1.5秒后偏离。 一旦第二个诺言被拒绝,从
Promise.all()返回的诺言就会被拒绝,而无需等待第一个
诺言 。
当您有多个承诺并且想知道所有承诺何时完成时,此方法很有用。 例如,如果您从第三方API请求数据,并且仅在所有请求成功后才想对这些数据做某事。
结果,我们有了
Promise.all() ,它等待所有promise的成功执行,或者在检测到promise数组中的第一个失败时完成其执行。
Promise.race()
此方法接受一个promise数组,并返回一个新的promise,如果该数组中的已实现promise早于被拒绝,则该新promise将在满足或被拒绝后立即执行。 例如:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 1000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('Promise2 '); }, 1500); }); Promise.race([promise1, promise2]) .then((data) => console.log(data))
在这里,我们有两个承诺,其中一个在1秒后执行,另一个在1.5秒后偏离。 一旦第一个诺言被实现,从Promise.race()返回的诺言将具有履行状态,而无需等待第二个诺言的状态。
在这里,传递给
then()的
数据是第一个执行的promise的值。
结果,
Promise.race()等待第一个promise,并将其状态作为返回的promise的状态。
翻译作者的评论:因此,名称本身。 种族-种族结论
我们了解了什么是诺言,以及它们在JavaScript中的作用。 承诺包括两个部分:1)创建承诺和2)使用承诺。 大多数时候,您将使用承诺而不是创建承诺,但是了解它们是如何创建的很重要。
仅此而已,希望本文对您有所帮助!