什么是PromisePromise是一个针对异步编程的解决方案。ES6中已经提供了原生的Promise对象。一个Promise对象会处于以下状态(fulfilled和rejected不会在确认后改变):Pending:初始状态,既没有fulfilled也没有rejected。Fulfilled:表示操作成功完成。Rejected:表示操作失败。基本用法Promise对象是一个用于创建Promise实例的构造函数,它接收resolve和reject两个参数。resolve的作用是将Promise对象的状态从pending变为fulfilled,异步操作成功时调用,将异步操作的结果作为参数传递。reject的作用是将Promise对象的状态从pending变为rejected,异步操作失败时调用,将异步操作报错作为参数传递。constpromise=newPromise(function(resolve,reject){//...if(/*异步操作成功*/){resolve(value);}else{reject(error);}});Promise实例生成后,使用then方法分别指定fulfilled状态和rejected状态的回调函数。然后接收两个参数,第一个是Promise对象状态变为fulfilled时的回调函数,第二个是状态变为rejected时的回调函数。当Promise对象的状态变为拒绝时,catch接收回调函数。promise.then(function(value){//....},function(err){//....err})promise.then(function(value){//....}).catch(function(err){//....})Promise的方法Promise.prototype.then()then方法定义在原型对象Promise.prototype上,前面提到过,它接收两个可选参数,第一个参数是fulfilled状态的回调函数,第二个参数是rejected状态的回调函数。then方法返回一个新的Promise实例,方便我们使用链式写法。例如,then后面跟着then。当第一个回调函数完成后,返回的结果将作为参数传递给第二个回调函数。这个链式方法可以方便的指定一组回调函数依次调用。loadData().then(function(value){return3}).then(function(num){console.log("ok",num)//3})Promise.prototype.catch()catch方法是为了指定发生错误时的回调函数。如果异步操作抛出错误,状态会变成rejected,调用catch()方法指定的回调函数处理错误。constpromise=newPromise(function(resolve,reject){thrownewError('unkonwerror');//Throwerrorstatebecomes->reject});constpromise=newPromise(function(resolve,reject){reject('unkonwerror')//使用reject()方法将状态更改为->reject});promise.catch(function(error){console.日志(错误);});Promise对象的错误会一直转到Post-passed直到被捕获。例如,下面的代码:catch将捕获在loadData和then中抛出的两个错误。loadData().then(function(value){returnloadData(value);}).then(function(users){}).catch(function(err){//处理前面三个Promises产生的错误});如果我们不设置catch(),Promise在遇到错误的时候不会把错误抛到外面,也就是不会影响外部代码的执行。constpromise=newPromise(function(resolve,reject){resolve(a)//ReferenceError:aisnotdefined});承诺。then(function(value){console.log('valueis',value)});setTimeout(()=>{console.log('codeisrun')},1000);//代码是runPromise.prototype.finally()finally()方法将执行操作,而不管Promise对象的最终状态如何。这是我们使用Promises的一般结构。promise.then(result=>{···}).catch(error=>{···}).finally(()=>{···});Promise.all()Promise.all()方法可以将多个Promise实例包装成一个新的Promise实例返回。constpromise=Promise.all([p1,p2,p3]);新的承诺状态取决于“传入的承诺”。只有当所有的“incomingpromise”状态都被fulfilled时,它的状态才会被fulfilled。此时“传入promise”的返回值组成一个数组,传递给promise的回调函数。如果其中一个“传入的承诺”被拒绝,新承诺的状态将变为拒绝,第一个被拒绝的承诺的返回值将传递给承诺的回调函数。constpromises=[1,2,3,4].map(function(id){returnloadData(id);});Promise.all(promises).then(function(users){//...}).catch(function(err){//...});Promise.race()Promise.race()方法还将多个Promise实例包装成一个新的Promise实例。Promise.race()方法采用与Promise.all()方法相同的参数。constpromise=Promise.race([p1,p2,p3]);Promise.all()与Promise.race()比较:Promise.all(),如果全部执行成功,则返回所有成功的promise值,如果有失败,则返回第一个失败的值。Promise.race(),返回第一个完成的promise值,它可能被完成或被拒绝。这两种方法的使用场景。场景一:用户登录社交网站首页后,会同时异步请求用户信息、关注列表、粉丝列表。在渲染页面之前,我们需要确保所有的数据请求都成功。只要任何数据不成功,页面就会被重定向。这里可以使用Promise.all。functioninitUserHome(){Promise.all([newPromise(getMe),newPromise(getFollows),newPromise(getFans)]).then(function(data){//显示页面}).catch(function(err){//....重定向页面});};initUserHome();场景2,如果我们做的是抢票软件,虽然请求了很多售票渠道,但是只需要返回第一个执行的每次Promise,这里都可以使用Promise.race。functiongetTicket(){Promise.race([newPromise(postASell),newPromise(postBSell),newPromise(postCSell)]).then(function(data){//抢票成功}).catch(function(err){//....抢票失败,重试});};getTicket();Promise.allSettled()使用Promise.all()时,如果一个Promise失败,其他Promise不会停止执行。constrequests=[fetch('/url1'),fetch('/url2'),fetch('/url3'),];尝试{awaitPromise.all(requests);console.log('所有请求都成功。');}catch{console.log('一个请求失败,其他请求可能还没有完成。');}有时候,我们想等到一组异步操作完成在进行下一步之前完成。这时候就需要用到Promise.allSettled(),它的参数是一个数组,每个成员都是一个Promise对象,返回一个新的Promise对象。它只会等到参数数组中的所有Promise对象都发生状态变化(无论是完成还是拒绝),然后返回的Promise对象才会改变状态。constrequests=[fetch('/url1'),fetch('/url2'),fetch('/url3'),];等待Promise.allSettled(请求);console.log('所有请求完成后(包括成功Failed)执行');Promise.any()只要传入的Promise中的一个变为fulfilled,新的Promise就会变为fulfilled;如果所有传入的Promise都被拒绝,则新的Promise将变为拒绝状态。Promise.any()类似于Promise.race(),不同的是Promise.any()不会在某个Promise被拒绝时结束,它必须等到所有参数承诺都被拒绝。回到Promise.race()多通道抢票的场景,如果我们需要保证要么一个通道抢票成功,要么所有通道都失败,那么使用Promise.any()更为合适。functiongetTicket(){Promise.any([newPromise(postASell),newPromise(postBSell),newPromise(postCSell)]).then(function(data){//抢票成功}).catch(function(err){//....allchannelsfailed});};getTicket();Promise.resolve()Promise.resolve()方法将现有对象转换为Promise对象。相当于下面的代码:newPromise(resolve=>resolve(1))传入的参数不同,对参数Promise实例进行处理,不做任何修改就会返回这个实例。参数thenable对象,它会把这个对象转成Promise对象,然后立即执行thenable对象的then()方法。让thenable={那么:函数(解决,拒绝){解决(1);}};参数为普通值,返回一个新的Promise对象,状态为resolved。constpromise=Promise.resolve(1);promise.then(function(value){console.log(value)//1});没有参数,直接返回一个处于解析状态的Promise对象。Promise.reject()Promise.reject(reason)方法还返回一个状态为拒绝的新Promise实例。constpromise=Promise.reject('unkonwerror');//相当于constpromise=newPromise((resolve,reject)=>reject('unkonwerror'))promise.then(null,function(s){console.log(s)});//未知错误简单场景异步加载图片:.onerror=reject;image.src=url;});}请求超时处理://requestfunctionrequest(){returnnewPromise(function(resolve,reject){//code....resolve('requestok')})}functiontimeoutHandle(time){returnnewPromise(function(resolve,reject){setTimeout(function(){reject('timeout');},time);});}Promise.race([请求(),timeoutHandle(5000)]).then(res=>{console.log(res)}).catch(err=>{console.log(err)//timeout})总结本文总结了Promise相关的方法和一些简单的用法,欢迎留言交流。
