Promises in JavaScript(译)

原文地址:Promises in JavaScript

现实生活中的承诺只是对“一些事情”的保证。因此,当有人向您承诺时会发生什么? 他们为您提供保证,您可以以此为基础进行提规划。 现在,诺言可以兑现也可以违背。 因此,当您信守诺言时,您会期望从诺言中得到一些东西。 您可以将promise的输出用于您的进一步操作或计划。 但是,当承诺违背时,您想知道为什么做出承诺的人不能跟上交易,而是会采取相应的下一个行动。JavaScript也提供了一种类似的“承诺”概念来处理异步调用。 本文涵盖以下主题,让我们了解“ JavaScript中的Promises”的详细信息:

  • JavaScript中的Promises是什么?
    • 何时在JavaScript中使用Promises?
    • Promises如何在JavaScript中工作?
  • 在JavaScript中创建Promise的过程。
  • 如何在JavaScript中使用Promise?
    • 如何使用.then()函数?
    • 如何使用.catch()函数?
    • 如何使用.finally()函数?
    • 如何将Promise.all()函数?
    • 如何使用Promise.race()函数?

JavaScript中的Promises是什么?

JavaScript中的Promise是持有异步操作未来值的对象。 例如,如果我们要从服务器请求一些数据,则promise承诺我们将获得将来可以使用的数据。

一个promise对象拥有如下状态:

States of a Promise

  • Pending:这是初始状态,结果尚未准备好,正在等待异步操作完成。
  • Resolved/Fulfilled:表示执行的操作已成功完成。 即,函数返回了承诺值。
  • Rejected:表示执行的操作失败或发生错误。 即函数未返回承诺值。

现在,让我们理解下在JavaScript中需要promise做些什么,因为通过回调它本身来处理异步操作。

何时在JavaScript中使用Promises?

正如我们在JavaScript中的回调文章中所讨论的那样,回调函数用于处理异步执行。 回调函数指示异步操作完成后JavaScript应该执行的操作。

这是运行中的回调函数的最简单示例:

<html>

	<body> Demonstrating callback in javascript:</br>
    	<script type="text/javascript">
    		function i_take_1_sec() {
                return setTimeout(() => {
                    document.write('I was no: 2 and I take 1 second</br>')
                }, 1000);
            }
            function i_take_10_sec(callback) {
                return setTimeout(() => {
                    document.write('I was no: 1 and I take 10 seconds</br>')
                    callback()
                }, 10000);
            }
            function run (){
                i_take_10_sec(i_take_1_sec);
            }
            run();
        </script>
    </body>

</html>

保存名称为callbackOne.html的文件,然后在任何浏览器(Chrome,Firefox或IE)中打开它。 它应该将输出显示为:

Callback: Ordering of functions in JavaScript

Promises如何在JavaScript中工作?

为了理解promise到底是如何工作的,让我们举个例子:考虑到您正在向母亲作出诺言,说您将在一天之后收拾完房间。 因此,可能发生两种可能的情况,要么您要打扫房间,要么不打扫房间并违背诺言。 让我们用JavaScript来写那个承诺。

let promiseCleanRoom = new Promise(function(resolve,reject){
    cleanRoom = true;
    if(cleanRoom){
      resolve('Cleaned the Room');
    }else{
      reject('Broke the promise');
    }
});

上面的代码块显示了如何创建承诺。 即,当执行此承诺时,它将基于cleanRoom值给出解决状态或拒绝状态。

我们可以将以上创建的promise称为或使用:

 promiseCleanRoom.then((result)=>{
      console.log(result)
  })

在上面的代码片段中,它显示了如何使用已创建的承诺,并且有“ .then”方法,该方法仅在满足或解决给定的承诺时才会执行某些操作。 在这种情况下,它将在解决时打印出诺言发送的结果,即"Cleaned the Room"

如果承诺被破坏或在这种情况下发生了一些错误,还会发生另外一种情况。 然后,我们可以使用“ .catch”块,该块将允许处理损坏的或错误的实例。

promiseCleanRoom.then((result)=>{
      console.log(result)
}).catch((result)=>{
   console.log(result) //will execute if promise is rejected or errored out
})

假设,如果诺言被破坏,那么它将通过跳过then块来执行catch块,并且输出将是“Broke the promise”。

注意:我们将在以下各节中详细介绍“ .then”和“ .catch”方法。

在JavaScript中如何创建一个Promise?

如上所述,JavaScript中的Promise是一个对象,代表异步操作的最终完成或失败。 其语法如下所示:

语法:

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

//do something

});

注意:我们使用Promise构造函数创建一个新的Promise,该构造函数使用一个参数,一个回调函数(也称为executor函数),该函数依次使用两个回调函数,resolve和reject。

promise创建后,executor函数立即执行。 promise通过调用resolve()方法进行解析,并通过调用reject()方法被拒绝。

在以下代码段的帮助下,让我们尝试了解Promise在JavaScript中的用法和工作方式。 在这里,我们将使用promise对象修改回调地狱程序(在回调文章中有所介绍)。

<html>

<body> Demonstrating promise in javascript:</br>
    <script type="text/javascript">

    	function i_take_10_sec()
    	{
    	 	return new Promise((resolve, reject)=>{
    	 	 	setTimeout(() => { 
    	 			resolve('I was no: 1 and I take 10 seconds');
    	 		}, 10000);
			})
    	}

    	function i_take_1_sec()
    	{ 
    		return new Promise((resolve, reject)=>{
    			setTimeout(() => { 
    				resolve('I was no: 2 and I take 1 second');
    			}, 1000);
    		}) 
    	}

    	function i_take_5_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
    				resolve('I was no: 3 and I take 5 second')
    			}, 5000); 
    		})
    	}

    	function i_take_7_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    			setTimeout(() => { 
    				resolve('I was no: 4 and I take 7 second')
    			}, 7000);
    		}) 
    	}

    
    	function run()
    	{
    		i_take_10_sec()
    		.then((result) => {
            console.log(result);
        		return i_take_1_sec()
   		})
    		.then((result) => {
            console.log(result);
        		return i_take_5_sec()
    		})
    		.then((result) => {
            console.log(result);
        		return i_take_7_sec()
    		})
    		.then((result)=>{
            console.log(result);
          })
    	}

    	run();

    </script>
</body>

</html>

使用promise.html名称保存文件,然后在任何浏览器(Chrome,Firefox或IE)中打开它。 它应该显示为

Understanding declaration and usage of promise in JavaScript

如上例所示,每个函数都返回一个使用“ .then()”链接到下一个的promise。 在这种情况下,代码流显得更漂亮和易于理解。

现在考虑一种promise被拒绝的情况。 因此,在那种情况下,它将引发错误,并且不会调用其他链接的函数调用。

让我们修改上面编写的程序,并且拒绝来自函数“ i_take_5_sec()”的promise,如下所示:

<html>
 
<body> Demonstrating promise in javascript:</br>
    <script type="text/javascript">
 
    	function i_take_10_sec()
    	{
     return new Promise((resolve, reject)=>{
     setTimeout(() => { 
     resolve('I was no: 1 and I take 10 seconds');
     }, 10000);
 })
    	}
 
    	function i_take_1_sec()
    	{ 
     return new Promise((resolve, reject)=>{
     setTimeout(() => { 
     resolve('I was no: 2 and I take 1 second');
     }, 1000);
     }) 
    	}
 
    	function i_take_5_sec(callback) 
    	{ 
     return new Promise((resolve, reject)=>{
     setTimeout(() => { 
     reject('I was no: 3 and I take 5 second')
     }, 5000); 
     })
    	}
 
    	function i_take_7_sec(callback) 
    	{ 
     return new Promise((resolve, reject)=>{
     setTimeout(() => { 
     resolve('I was no: 4 and I take 7 second')
     }, 7000);
     }) 
    	}
 
    
    	function run()
    	{
     i_take_10_sec()
     .then((result) => {
            console.log(result);
         return i_take_1_sec()
   })
     .then((result) => {
            console.log(result);
         return i_take_5_sec()
     })
     .then((result) => {
            console.log(result);
         return i_take_7_sec()
     })
     .then((result)=>{
            console.log(result);
          })
    	}
 
    	run();
 
    </script>
</body>
 
</html>

命名为promise.html并保存文件,然后在任何浏览器(Chrome,Firefox或IE)中打开它。 它应该显示为

Understanding rejection of promise in JavaScript

从上面的屏幕截图可以看出,JavaScript在调用方法“ i_take_5_sec”后引发了“Uncaught”错误,并且没有其他代码语句执行。 因此,这证实了,promise一旦“rejected”了,它将导致所有进一步链接的命令失败。

如何在JavaScript中使用promise?

通过使用.then,.catch和.finally方法注册函数来消费promise。 Promise对象用作执行程序和消费函数之间的链接,执行器和接收函数将接收结果或错误,并且使用函数可以使用.then,.catch或.finally方法中的任何一种。 让我们在以下各节中查看所有这些方法的用法:

如何使用.then()作为消费者函数?

.then()方法在一个promise明确resolved或rejected时调用。 其语法如下所示:

语法:

.then(function(result){
        //statements when the promise is resolved successfully
    }, function(error){
        //statements when the prmise was rejected or raised an error
    })

通过下图,我们可以了解“ .then()”方法的主要用法:
usage of .then method

让我们以这种方式理解,假设一条if-else语句,其中当给定条件为true时,if块中的代码将执行; 否则,它将执行else块。 同样,“ then”方法将使用两个函数作为参数,第一个函数将在promise成功解决后运行,或者在promise拒绝或引发错误时执行第二个方法。

通过修改上面编写的程序,让我们了解“ .then()消费者方法”的用法和实现:

<html>

<body> Demonstrating promise consumer using .then()  method in javascript:</br>
    <script type="text/javascript">

    	function i_take_10_sec()
    	{
    	 	return new Promise((resolve, reject)=>{
    	 	 	setTimeout(() => { 
    	 			resolve('I was no: 1 and I take 10 seconds');
    	 		}, 10000);
			})
    	}

    	function i_take_5_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
    				reject('I was no: 3 and I take 5 second')
    			}, 5000); 
    		})
    	}
    
    	function run()
    	{
    		i_take_10_sec()
    		.then((result) => {
                        console.log(result);
        		return i_take_5_sec()
   		})
    		.then((result)=>{
                   console.log(result);
                 },()=>{
                    console.log('Error Raised')
                 })
    	}

    	run();

    </script>
</body>

</html>

保存名称为promiseThen.html的文件,然后在任何浏览器(Chrome,Firefox或IE)中打开它。 它应该将输出显示为:

handling promise using .then() method in JavaScript

从上面的屏幕截图中我们可以看到,由于“ i_take_5_sec()”方法导致承诺被拒绝,因此run方法中的调用流调用了第二个函数,而不是第一个函数。 因此,以这种方式,用户可以根据promise的预期输出,使用“ .then()”方法控制程序的执行流程。

但是,传递两个函数作为then方法的参数看起来有些混乱。 因此,为克服此问题,引入了“ .catch”块或函数,当出现拒绝或发生某些错误时,catch块将显式处理。

如何使用.catch()作为消费者函数?

当承诺被拒绝或执行中发生错误时,.catch()方法将调用。 其语法如下所示:

语法:

.catch(function(error){
        //Statements to handle error raised
    })

下图可以帮助您理解“ .catch()”方法的基本用法:

usage of .catch method for rejection of promise in JavaScript

从上图可以明显看出,在指定.catch()方法的情况下,当承诺被拒绝时,它将调用“ .catch”块。

让我们通过如下修改上述编写的程序来了解“ .catch()消费者函数”的用法和实现:

<html>

<body> Demonstrating promise consumer using .catch() method in javascript:</br>
    <script type="text/javascript">

    	function i_take_10_sec()
    	{
    	 	return new Promise((resolve, reject)=>{
    	 	 	setTimeout(() => { 
    	 			resolve('I was no: 1 and I take 10 seconds');
    	 		}, 10000);
			})
    	}

    	function i_take_5_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
    				reject('I was no: 3 and I take 5 second')
    			}, 5000); 
    		})
    	}
    
    	function run()
    	{
    		i_take_10_sec()
    		.then((result) => {
                        console.log(result);
        		return i_take_5_sec()
   		})
    		.then((result)=>{
                    console.log(result);
                }).catch(()=>{
                   console.log('Error Raised')
               })
    	}

    	run();

    </script>
</body>

</html>

使用名称promiseCatch.html保存文件,然后在任何浏览器(Chrome,Firefox或IE)中打开文件。 它应该将输出显示为:

using catch to handle rejected promise in JavaScript

从上面的屏幕截图中我们可以看到,由于“ i_take_5_sec()”方法导致承诺被拒绝,因此调用流程引发了异常,该异常发生在.catch()块中。 另外,由于异常发生得当,它不会阻止调用流程,并且仍然会执行“ Done”打印所产生的.then()部分中的下一部分。 很明显,即使中间调用之一导致错误或异常,使用.catch()块也可以确保继续执行进一步的链接调用。

如何使用.finally()作为消费者者函数?

我们过去经常使用在try{...}catch{...}语句中使用finally块,在promises也有finally。当promise完成后这个消费者函数总是会执行,无论是resolve或者reject。finally块是执行清理操作的良好处理程序,我们一直希望执行该处理程序。其语法如下所示:

.finally(() => {
 // Statements which are expected to be executed always
})

下图可以帮助您理解“ .finally()”方法的基本用法:

finally clause to handle a promise in JavaScript

从上图可以看出,无论promise是否resolved或者rejected,“ finally”块始终都会执行。

通过修改上面编写的程序,让我们在“ .finally()消费者方法”的用法和实现下进行以下操作:

<html>

<body> Demonstrating promise consumer using .finally() method in javascript:</br>
    <script type="text/javascript">

    	function i_take_10_sec()
    	{
    	 	return new Promise((resolve, reject)=>{
    	 	 	setTimeout(() => { 
    	 			resolve('I was no: 1 and I take 10 seconds');
    	 		}, 10000);
			})
    	}

    	function i_take_5_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
    				reject('I was no: 3 and I take 5 second')
    			}, 5000); 
    		})
    	}
    
    	function run()
    	{
    		i_take_10_sec()
    		.then((result) => {
            console.log(result);
        		return i_take_5_sec()
   		})
    		.then((result)=>{
            console.log(result);
          }).catch(()=>{
             console.log('Error Raised')
          }).finally(()=>{
             console.log('Completed Execution')
          })
    	}

    	run();

    </script>
</body>

</html>

保存名称为promiseFinally.html的文件,然后在任何浏览器(Chrome,Firefox或IE)中打开它。 它应该将输出显示为:

Using finally clause to handle promise in JavaScript

从上面的屏幕截图中我们可以看到,由于“ i_take_5_sec()”方法导致承诺被拒绝,因此引发了异常,并且未执行“ Done”块的下一个.then()方法。 但是,仍然可以从输出中看到执行了finally()块。 因此,很清楚,无论promise返回已解决,已拒绝还是错误状态,都将始终执行“ finally()”块。

如何使用Promise.all()作为消费者函数?

如果你需要并行执行多个promise,并且想要在所有promise完成之后继续执行,则可以使用JavaScript中Promises提供的“ .all”函数。 它接受一个promises函数数组,并同时/并行执行所有函数,然后等到所有promise都被rejecte或resolve为止。 其语法如下所示:

Promise.all([array of promises]);

通过以下示例,让我们了解“ Promise.all”的用法:

示例:

<html>

<body> Demonstrating promise all() method in javascript:</br>
    <script type="text/javascript">

    	function i_take_10_sec()
    	{
    	 	return new Promise((resolve, reject)=>{
    	 	 	setTimeout(() => { 
               console.log('I was no: 1 and I take 10 second')
    	 			resolve('I was no: 1 and I take 10 seconds');
    	 		}, 10000);
			})
    	}

    	function i_take_5_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
               console.log('I was no: 2 and I take 5 second')
    				resolve('I was no: 2 and I take 5 second')
    			}, 5000); 
    		})
    	}

      function i_take_7_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
               console.log('I was no: 3 and I take 7 second')
    				resolve('I was no: 3 and I take 7 second')
    			}, 7000); 
    		})
    	}
    
    	function run()
    	{
    		Promise.all([i_take_10_sec(),i_take_5_sec(),i_take_7_sec()]).then(()=>{
             console.log("All finished");
          })
    	}

    	run();
    </script>
</body>

</html>

保存名称为promiseAll.html的文件,然后在任何浏览器(Chrome,Firefox或IE)中打开它。 它应该将输出显示为:

usage of Promise.all() method

我们可以看到,所有的promise都在同时执行,并且会等到所有promise已经resolve或reject为止。

注意:Promise.all()不能确保promise的任何顺序。 它只是并行执行所有promise。

如何使用Promise.race()作为消费者函数?

如果您想并行执行多个promise,但又不想等待所有promise的完成再继续进行,则可以使用JavaScript中Promises提供的“ .race”函数。 它只是等待任何一个promise的完成,然后首先返回。 它将使用一组promise函数并同时执行所有函数,并等待直到任何一个promise已经resolve或reject为止。 其语法如下所示:

Promise.race([array of promises])

在以下示例的帮助下,我们了解“ Promise.race”的用法:

示例:

<html>

<body> Demonstrating promise race() method in javascript:</br>
    <script type="text/javascript">

    	function i_take_10_sec()
    	{
    	 	return new Promise((resolve, reject)=>{
    	 	 	setTimeout(() => { 
               console.log('I was no: 1 and I take 10 second')
    	 			resolve('I was no: 1 and I take 10 seconds');
    	 		}, 10000);
			})
    	}

    	function i_take_5_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
               console.log('I was no: 2 and I take 5 second')
    				resolve('I was no: 2 and I take 5 second')
    			}, 5000); 
    		})
    	}

      function i_take_7_sec(callback) 
    	{ 
    		return new Promise((resolve, reject)=>{
    		 	setTimeout(() => { 
               console.log('I was no: 3 and I take 7 second')
    				resolve('I was no: 3 and I take 7 second')
    			}, 7000); 
    		})
    	}
    
    	function run()
    	{
    		Promise.race([i_take_10_sec(),i_take_5_sec(),i_take_7_sec()]).then(()=>{
             console.log("All finished");
          })
    	}

    	run();
    </script>
</body>

</html>

保存名称为promiseRace.html的文件,然后在任何浏览器(Chrome,Firefox或IE)中打开它。 它应该将输出显示为:

Usage of Promise.Race method

在上面的示例中,我们可以看到,一个promise(i_take_5 sec)一旦resolve,它就会从then函数中退出。

重点

  • promise可以处理JavaScript中的异步调用。
  • 根据异步调用的响应,promise在执行时将处于“pending”状态,并导致“resolved”或“rejected”。
  • promise避免由于嵌套的回调函数而发生的“回调地狱”问题。

现在,让我们转到下一篇文章“ DOM Manipulation”,那里我们将介绍JavaScript提供的各种概念/功能,DOM将使用这些概念/功能 可以在运行时动态地进行操作

posted @ 2020-09-20 17:13  mingL  阅读(216)  评论(0编辑  收藏  举报