ECMAScript6增加了对Promises/A+规范的全面支持,即Promise类型。一经推出,Promises就变得流行起来,并成为占主导地位的异步编程机制。所有现代浏览器都支持ES6契约,许多其他浏览器API都是基于契约的。Promise是ECMAScript6中的一种新的引用类型,它代表了一个异步操作的最终完成或失败。创建对象的Promise语法如下:letpromise=newPromise(function(resolve,reject)=>{//异步处理//resolve(value)//fulfilled//or//reject(error)//rejected});从上面可以看出,Promise是一个有状态的对象,返回的Promise对象可能处于以下状态之一:Pending:初始状态,即还没有被fulfilled或者rejected。fulfilled(有时也称为“solved”、resolved):表示操作成功完成。Rejected:表示操作失败。Pending是Promise的初始状态。在pending状态下,Promise可以是settled(fulfilled)状态表示成功,也可以是rejected(拒绝)状态表示失败。无论进入哪种状态,都是不可逆转的。只要Promise从pending过渡到fulfilled或rejected,它的状态就永远不会改变。此外,也不能保证Promise一定会脱离pending状态。因此,无论Promise是resolves、rejects还是永远停留在pending状态,组织良好的代码都应该有适当的行为。重要的是,Promise的状态是私有的,无法通过JavaScript直接检测到。这主要是为了避免根据读取的Promise状态同步处理Promise实例。此外,Promise的状态不能被外部JavaScript代码修改。这与无法读取状态的原因相同:Promises有意封装异步行为以隔离外部同步代码。Promise实例方法Promise实例的方法是外部同步代码和内部异步代码之间的桥梁。这些方法可以访问异步操作返回的数据,处理Promise对象的成功和失败,持续评估Promise,或者添加只有当Promise进入最终状态时才会执行的代码。Promise.prototype.then()Promise.prototype.then()方法返回一个Promise实例,是为Promise实例添加处理的主要方法。Promise.prototype.then(onFulfilled,onRejected)onFulfilled:可选参数。当Promise状态变为fulfilled时调用的函数。传入的任何非函数类型都会被忽略。onRejected:可选参数。当Promise状态变为拒绝时调用的函数。传入的任何非函数类型都会被忽略。当value提供onRejected参数时,需要上传undefined来代替onFulfilled参数。有助于避免在内存中创建冗余对象,并且是对需要函数参数的类型系统的回答。Promise.prototype.catch()Promise.prototype.catch()方法返回一个Promise实例并处理拒绝。Promise.prototype.catch(onRejected)onRejected:当Promise被拒绝时调用的函数。这个函数有一个参数reason,表示拒绝的原因。如果onRejected抛出错误或返回一个本身失败的Promise,则catch()返回的Promise将被拒绝;否则,它将显示为成功(已解决)。此方法可用于promise组合中的错误处理。其实这个方法是一个语法糖,调用它相当于Promise.prototype.then(null,onRejected)。Promise.prototype.finally()Promise.prototype.finally()方法返回一个Promise实例,当Promise处理结束时,无论状态如何,都会执行指定的回调函数。这为无论Promise是否成功完成都需要执行的代码提供了一种方法。还要避免then()和catch()中的冗余代码。Promise.prototype.finally(onFinally)onFinally:收到Promise时调用的函数。但是上面的onFinally函数并不能知道Promise处于什么状态,所以这个方法主要用来添加清理代码。错误处理状态为rejected的Promise类似于throw()表达式,两者都表示需要中断或特殊处理的程序状态。Promise执行过程中抛出的错误会导致rejected,对应的Error会成为reject的原因。让p=newPromise((resolve,reject)=>reject(throwError('ErrorValue')));在Promise实例中抛出错误会从消息队列中异步抛出,不会阻止运行时继续执行同步命令:Promise.reject(Error('ErrorValue'));console.log('initialvalue');//initialvalue//Uncaught(inpromise)Error:ErrorValue因此,Promise只能通过catch实例方法捕获错误,try-catch块效果不好。Promise的then和catch方法相当于try-catch。Promise静态方法Promise引用类型中有多个静态方法。除了Promise.reject()和Promise.resolve()之外,它们都接收一个Promise的可迭代类型的参数。合成的Promise的行为取决于内部Promise的行为。注意:Promise.any()方法是实验性的,尚未得到完全支持。Promise.reject()Promise.reject()返回状态为rejected的Promise实例并抛出异步错误。Promise.reject(原因);reason:表示Promise实例的失败信息。使用Promise.reject()实际上与newPromise((resolve,reject)=>reject())相同。在传入错误原因时,可以传入一个Error实例,使其成为返回的Promise实例的错误原因:Promise.reject(newError("Promiseinstancefailed")).then(function(){//notcalled},function(error){console.error(error);//Stacktrace});setTimeout(console.log,0,Promise.reject(Promise.resolve()));//Promise:PromisePromise.resolve()通过Promise.resolve()静态方法可以实例化一个状态为fulfilled的Promise实例。实际上与newPromise((resolve,reject)=>resolve())相同。Promise.resolve(value)value:Promise实例对象要解析的参数,也可以是Promise实例或thenable。使用这个静态方法,可以将任何值转换为状态为fulfilled的Promise实例,传入的额外值将被忽略。setTimeout(console.log,0,Promise.resolve());//Promise:undefinedsetTimeout(console.log,0,Promise.resolve(4,5,6));//Promise:4当传入的参数本身是一个Promise实例时,它的行为就像一个空包装器。因此,Promise.resolve()可以说是一个幂等方法。letp=Promise.resolve(7);setTimeout(console.log,0,p===Promise.resolve(p));//truesetTimeout(console.log,0,p===Promise.resolve(Promise.resolve(p)));//真正的幂等性将保留传入合约的状态:letp=newPromise(()=>{});setTimeout(console.log,0,p);//PromisesetTimeout(console.log,0,Promise.resolve(p));//PromisesetTimeout(console.log,0,p===Promise.resolve(p));//truehowever,它本身包装了任何非Promise值,包括错误对象,并将其转换为已解析的Promise实例,这可能会导致意外行为。注意:letp=Promise.resolve(newError('foo'));setTimeout(console.log,0,p);//Promise:Error:fooPromise.all()Promise.all()方法接收Promise实例的可迭代集合并返回一个新的Promise实例。当所有的Promise实例状态变为fulfilled时,返回的Promise实例的状态变为fulfilled,resolved值是一个数组,包含Promise实例的所有resolved值,按迭代器顺序排列。让p=Promise.all([Promise.resolve(3),Promise.resolve(),Promise.resolve(4)]);p.then((values)=>setTimeout(console.log,0,values));//[3,undefined,4]当一个Promise实例的状态变为rejected时,返回的Promise实例的状态变为rejected,返回的rejectionreason为状态变为rejected的Promise实例的拒绝原因。Promise实例的后续拒绝不会影响最终Promise的拒绝原因。但是,这并不影响正常拒绝所有包含的Promise实例。Promise.all返回的Promise实例静默处理所有包含Promise实例的拒绝,如下所示://虽然只有第一个promise的拒绝原因进入//拒绝处理程序,第二个promise的拒绝也会//??//将静默处理,没有错误会跑掉letp=Promise.all([Promise.reject(3),newPromise((resolve,reject)=>setTimeout(reject,1000))]);p。catch((原因)=>setTimeout(console.log,0,原因));//3//没有未处理的错误Promise.allSettled()ECMAScript2020添加了Promise.allSettled()方法。在Promise.allSettled()方法接收到的可迭代集合中,Promise实例的状态是fulfilled或rejected。Promise.allSettled([Promise.resolve(3),newPromise((resolve,reject)=>{setTimeout(reject,1000);}),Promise.reject('拒绝承诺')]).then((结果)=>console.log(results));/***输出结果*[*{status:'fulfilled',value:3},*{status:'rejected',reason:undefined},*{status:'rejected',reason:'rejectpromise'}*]*/Promise.allSettled()方法在您要确保所有Promise实例都已解析时很有用。Promise.race()在Promise.race()方法接收到的可迭代集合中,只要有状态变为fulfilled或rejected的Promise实例,就会将其解析值或拒绝原因包装起来,并生成一个新的Promise实例回。//resolve先发生,超时后拒绝被忽略letp1=Promise.race([Promise.resolve(3),newPromise((resolve,reject)=>setTimeout(reject,1000))]);setTimeout(console.日志,0,p1);//Promise:3//拒绝先发生,超时后的解决被忽略letp2=Promise.race([Promise.reject(4),newPromise((resolve,reject)=>setTimeout(resolve,1000))]);setTimeout(console.log,0,p2);//Promise:4与Promise.all()类似,被拒绝的Promise实例中的拒绝原因变为Promise.race()的拒绝原因,可迭代集合中剩余的Promise实例将被静默处理,不再错误会消失。//虽然只有第一个合约的拒绝原因会进入拒绝处理器,但是第二个合约的拒绝也会被静默处理,不会有错误跑掉letp=Promise.race([Promise.reject(3),newPromise((resolve,reject)=>setTimeout(reject,1000))]);p.catch((reason)=>setTimeout(console.log,0,reason));//3//NoneUnhandlederrorchaincallsPromise提供的then(),catch()和finally()方法都会返回一个新的Promise实例,新的Promise实例可以调用这些方法,方法调用可以链式调用形成链式调用。像这样:letp=newPromise((resolve,reject)=>{console.log('initialpromise');reject();}).catch(()=>{console.log('rejecthandler');}).then(()=>{console.log('resolvehandler');}).finally(()=>{console.log('finallyhandler');});/***输出结果*initialpromise*rejecthandler*resolvehandler*finallyhandler*/链式调用会按顺序执行,每个Promise都会等待上一个Promiseresolve,然后实例化一个新的Promise实例返回,这样的结构可以简洁序列化异步任务。letp=newPromise((resolve,reject)=>{console.log('initialpromise');setTimeout(resolve,1000);}).then(()=>newPromise((resolve,reject)=>{console.log('firstpromise');setTimeout(resolve,3000);})).then(()=>newPromise((resolve,reject)=>{console.log("secondpromise");setTimeout(resolve,2000);})).then(()=>newPromise((resolve,reject)=>{console.log("thirdpromise");setTimeout(resolve,1000);}));/***输出结果*初始承诺*第一次承诺*第二次承诺*第三次承诺*/更多内容请关注公众号「海人为记」