当前位置: 首页 > 后端技术 > Node.js

Promise对象的理解

时间:2023-04-03 15:45:20 Node.js

Promise含义Promise是一种异步编程的解决方案,比传统的解决方案——回调函数和事件更合理、更强大。它是由社区首先提出并实施的。ES6将其写入语言标准,统一使用,原生提供Promise对象。所谓Promise,简单来说就是一个容器,里面装的是将来会结束的事件(通常是异步操作)的结果。从语法上讲,Promise是一个对象,可以从中获取异步操作的消息。Promise提供了统一的API,各种异步操作可以统一处理。Promise对象具有以下两个特点:对象的状态不受外界影响。共有三种状态,pending(进行中),fulfilled(成功),rejected(失败)。状态一旦改变,就不会再改变,随时都可以得到这个结果。状态变化只有两种可能:从pending到fulfilled和从pending到rejected。使用Promise对象的好处是可以在同步操作的过程中表达异步操作,避免层层嵌套的回调函数。Promise对象提供统一的接口,可以更轻松地控制异步操作??。Promise的缺点:Promise不能被取消。一旦创建,将立即执行,不能中途取消。如果没有设置回调函数,Promise内部抛出的错误将不会反映到外部。当处于pending状态时,无法得知当前进度处于哪个阶段(刚刚开始还是即将完成)。基本用法ES6规定Promise对象是一个用于生成Promise实例的构造函数。constpromise=newPromise((resolve,reject)=>{setTimeout(()=>{constnum=Math.random();if(num>0.5){resolve(num);}else{reject(num);}},500);});promise.then(res=>{console.log("成功:"+res);},err=>{console.log("失败:"+err);});Promise构造函数接受一个函数作为参数,该函数的两个参数是resolve和reject。它们是两个函数,由JavaScript引擎提供,你不需要自己部署。resolve函数的作用:将Promise对象的状态从“pending”变为“resolved”,在异步操作成功时调用,将异步操作的结果作为参数传递。reject函数的作用:当异步操作失败时,将Promise对象的状态从“pending”变为“rejected”,并将异步操作报错作为参数传递。then方法功能:接受两个回调函数作为参数。当Promise对象的状态变为已解决时调用第一个回调函数,当Promise对象的状态变为拒绝时调用第二个回调函数。第二个函数是可选的,不是必须提供的。您还可以将第二个函数用作catch方法的参数。catch方法功能:用于指定发生错误时的回调函数。如果Promise对象的异步操作抛出错误,状态会变为rejected,调用catch方法指定的回调函数处理错误。另外,如果then方法指定的回调函数在运行过程中抛出错误,也会被catch方法捕获。constpromise=newPromise((resolve,reject)=>{setTimeout(()=>{constnum=Math.random();if(num>0.5){resolve(num);}else{reject(num);}},500);});promise.then(res=>{console.log("成功:"+res);}).catch(err=>{console.log("失败:"+err);});promise.then(res=>{console.log("Success:"+res);thrownewError("test");}).catch(err=>{//print"Failedwhennum>0.5:Error:test"console.log("失败:"+err);});Promise执行顺序Promise在新建后会立即执行,then方法指定的回调函数会在当前脚本的所有同步任务执行完毕后执行,同理catch。调用resolve或reject不会终止Promise的参数函数的执行。constpromise=newPromise((resolve,reject)=>{console.log("我是第一个执行的");resolve();});promise.then(res=>{console.log("我是第三次执行");});console.log("我是第二次执行");resolve函数和reject函数的参数reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值外,还可能是另外一个Promise实例。如果一个Promise(P2)的resolve参数是另一个Promise(P1),此时P1的状态会传递给P2,P1的状态决定P2的状态。当P1的状态改变时,P2的回调函数就会被执行。constp1=newPromise(function(resolve,reject){setTimeout(()=>reject(newError("fail")),3000);});constp2=newPromise(function(resolve,reject){setTimeout(()=>resolve(p1),1000);});p2.then(result=>console.log(result)).catch(error=>console.log(error));//Error:failabove在代码中,p1是一个Promise,它在3秒后被拒绝。1秒后p2的状态发生变化,resolve方法返回p1。由于p2返回了另一个Promise,所以p2的状态是无效的,p2的状态由p1的状态决定。所以,后面的then语句都是针对后者(p1)的。又过了2秒,p1变成rejected,触发catch方法指定的回调函数。Promise链调用then方法可以返回一个新的Promise实例(注意,不是原来的Promise实例)。所以可以采用链式写法,即在then方法之后再调用一个then方法。constpromise=newPromise((resolve,reject)=>{resolve("promise");}).then(res=>{console.log(res);//promisereturn"promise1";}).then(res=>{console.log(res);//promise1return"promise2";}).then(res=>{console.log(res);//promise2});注意:只有一个Promise抛出错误,catch方法会被执行,then链会终止。constpromise=newPromise((resolve,reject)=>{resolve("promise");}).then(res=>{console.log(res);//promisethrownewError("abort");return"promise1";}).then(res=>{console.log(res);return"promise2";}).then(res=>{console.log(res);}).catch(err=>{console.log(err);//错误:中止});主动终止then链,使用catch方法中止promise链constpromise=newPromise((resolve,reject)=>{resolve("promise");})。then(res=>{console.log(res);//promisereturnPromise.reject({notRealPromiseException:true});}).then(res=>{console.log(res);return"promise2";}).then(res=>{console.log(res);}).catch(err=>{if(err.notRealPromiseException){returntrue;}console.log(err);});Promise.prototype.finally()finally方法用于指定将执行的操作,无论Promise对象的最终状态如何。该方法由ES2018引入标准。finally本质上是then方法的特例,不接受任何参数,不依赖于Promise的执行结果promise.finally(()=>{//statement});//等价于promise.then(result=>{//语句返回结果;},error=>{//语句抛出错误;});Promise.all()Promise.all方法用于将多个Promise实例包装成一个新的Promise实例。constpromise=Promise.all([promise1,promise2,promise3])Promise.all方法接受一个数组作为参数。Promise、probeige和promise3都是Promise实例。如果不是,会调用下面提到的Promise.resolvefirst方法,将参数转化为Promise实例,再进行进一步的处理。(Promise.all方法的参数可以不是数组,但必须有Iterator接口,返回的每个成员都是一个Promise实例。了解Iterator接口)promise的状态由promise1,promise2,和promise3,可以分为两种情况。只有当promise1、promise2和promise3的状态变为fulfilled时,p的状态才会变为fulfilled。此时promise1、promise2、promise3的返回值组成一个数组,传递给p的回调函数。只要promise1、promise2、promise3中的一个被拒绝,promise的状态就变成了被拒绝。这时候第一个被拒绝的实例的返回值就会传递给promise的回调函数。constp1=newPromise((resolve,reject)=>{resolve("hello");}).then(result=>result).catch(e=>e);constp2=newPromise((resolve,reject)=>{thrownewError("报告错误");}).then(result=>result).catch(e=>e);Promise.all([p1,p2]).then(result=>console.log(result)).catch(e=>console.log(e));//["hello",Error:报错]上面代码中,p1会被resolved,p2会先被reject,但是p2有自己的catch方法,返回一个新的Promise实例,而p2其实指向的就是这个实例。实例执行catch方法后,也会变成resolved,导致promise.all()方法参数中的两个实例都被resolved,所以会调用then方法指定的回调函数,而不是回调函数由catch方法指定。如果p2没有自己的catch方法,就会调用Promise.all()的catch方法。Promise.race()Promise.race方法还将多个Promise实例包装成一个新的Promise实例。constp=Promise.race([p1,p2,p3])只要p1,p2,p3中有一个实例先改变状态,p的状态就会随之改变。第一个变异的Promise实例的返回值被传递给p的回调函数。Promise.race方法的参数与Promise.all方法的参数相同。如果不是Promise实例,会先调用下面提到的Promise.resolve方法将参数转化为Promise实例,再进行进一步处理。Promise.resolve()将现有对象转换为Promise。constpromise=Promise.resolve('Helloworld')参数是Promise实例,这个方法不会改变任何东西。参数是一个thenable对象,先将该对象转为Promise对象,然后立即执行thenable方法。相当于将thenable对象中then方法处理后的值作为参数传递给promisethen方法。让thenObj={then(resolve,reject){resolve("Hello");}};constpromise=Promise.resolve(thenObj);promise.then(res=>{console.log(res);//你好});参数不是有then方法的对象,或者根本不是对象,那么Promise.resolve方法返回一个状态为resolved的新Promise对象。Promise.reject()Promise.reject(reason)方法还返回一个状态为拒绝的新Promise实例。