了解JavaScript承诺

美好的一天,哈伯! 我向您介绍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个回调, resolvereject

创建承诺后,立即执行执行功能。 通过调用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将随机执行或拒绝,其值将是传递给resolvereject函数的值。 下面是两种情况的示例:

成功完成:



承诺拒绝:



注意:承诺只能执行一次或拒绝一次。 进一步调用solve()reject()不会以任何方式影响promise的状态。 一个例子:

 const promise = new Promise((resolve, reject) => { resolve('Promise resolved'); //   reject('Promise rejected'); //       }); 

由于首先调用了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); //  '  !' }, (error) => { console.log(error); //   } ); 

如果已执行诺言,则使用传递给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  return promise2; }) .then((data) => { console.log(data); // Promise2  return promise3; }) .then((data) => { console.log(data); }) .catch((error) => { console.log(error); // Promise3  }); 

那么这是怎么回事?


满足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); // Promise1  promise2.then((data) => { console.log(data); // Promise2  promise3.then((data) => { console.log(data); }).catch((error) => { console.log(error); // Promise3  }); }).catch((error) => { console.log(error); }) }).catch((error) => { console.log(error); }); 

尽管这可以很好地工作,但是它被认为是不好的样式,并且使代码的可读性降低。 如果您要执行一系列承诺,最好将它们一个接一个地放置,而不是一个放入另一个内。

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)); // Promise2  

在这里,我们有两个承诺,其中一个在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)) // Promise1  .catch((error) => console.log(error)); 

在这里,我们有两个承诺,其中一个在1秒后执行,另一个在1.5秒后偏离。 一旦第一个诺言被实现,从Promise.race()返回的诺言将具有履行状态,而无需等待第二个诺言的状态。

在这里,传递给then()数据是第一个执行的promise的值。

结果, Promise.race()等待第一个promise,并将其状态作为返回的promise的状态。

翻译作者的评论:因此,名称本身。 种族-种族

结论


我们了解了什么是诺言,以及它们在JavaScript中的作用。 承诺包括两个部分:1)创建承诺和2)使用承诺。 大多数时候,您将使用承诺而不是创建承诺,但是了解它们是如何创建的很重要。

仅此而已,希望本文对您有所帮助!

Source: https://habr.com/ru/post/zh-CN439746/


All Articles