Promise是?
- es6之前,js解决异步的方案是 回调函数,这会带来一系列的问题,尤其是回调里嵌套回调导致的回调地狱;
如:
// 定义一个1s后执行callback的异步apifunction late1sCallback(callback){setTimeout(callback,1000);}//感受下回调地狱吧!凡人!late1sCallback(function(){late1sCallback(function(){late1sCallback(function(){console.log('这是一个打印,目测约在3s后执行');})})})
于是社区就有了对应的封装解决方案,基于callback这种形式封装了一个Promise类,用起来比较方便,解决了上面的问题。
再于是乎,定义ES规范的大人物们觉得还不错,就在ES6把Promise给规范了(就是内置了Promise类)。
new Promise 与 .then属性
那么我们先学习Promise的简单使用 new Promise与 .then:
new Promise(late1sCallback) // 返回一个promise对象.then(()=>{console.log('这是一个打印,目测1s后执行')}).then(()=>{console.log('这是一个打印,上一个执行完了这个才会执行')})
ok,我们到这能看到,其实Promise就是把callback参数的形式放到了 .then里;
并且.then后能够继续.then,这叫做链式调用,我们之前讲过它的实现,无非是返回了一个promise对象;那么我们试图封装它:
```javascript // 这里一共用了四行代码,实现了这种形式的异步api封装
function MyPromise(asyncFn){ this.then = function(callback){ // callback就是resolveasyncFn(callback);return this; // this就是Promise实例化对象
} }
// 试一试 function late1sCallback(callback){ setTimeout(callback,1000); }
new MyPromise(late1sCallback) .then(function(){console.log(1)}) .then(function(){console.log(2)})
那么Promise我们就简单的封装完了,虽然只实现了.then功能,并且有一定缺陷(没有队列控制,没有容错,没有参数传递等);<br />当然,promise对象不可能只有一个.then功能,那么我们将深入学习下promise<a name="5vsue"></a>### Promise.resolve`**Promise.resolve(value)**`方法返回一个以给定值解析后的[`Promise`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise) 对象。如果这个值是一个 promise ,那么将返回这个 promise ;如果这个值是thenable(即带有[`"then" `](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;否则返回的promise将以此值完成。此函数将类promise对象的多层嵌套展平。<br />上述看起来不好理解?没关系,看下面的代码:```javascriptconst promise = Promise.resolve(2);// 这个api接受一个值作为参数,返回的是一个promise对象promise.then(value =>console.log(value));//打印2 也就是说,上面的参数值会作为第一个.then的形参。 当然.then也会返回一个promise对象。// 因此它们都可以链式调用Promise.resolve(5).then(value=>{console.log(value); //5return value +1; // 返回值作为下一个.then的形参}).then(data=>console.log(data)) // 6
然后是关于 thenable参数的解读。 意思是如果传入的参数,含有.then的属性(它有可能是一个promise对象,也有可能是一个含有.then属性的普通对象),比如:
// 案例1Promise.resolve({then:(callback,failCallback)=>{callback('嘿嘿')}}) // 传入了一个含有.then属性的对象.then(console.log) // 嘿嘿// 案例2const p = new Promise(function(callback){callback('哈哈')})Promise.resolve(p).then(console.log) // 哈哈
要注意的是 如果promise.resolve的参数值是一个thenable,那么它的resolve是一个异步的( 因为.then的callback是异步执行的 )。
Promise.all
试想这样一个场景,某个页面级组件可能要在初始化后请求多个接口,并且要等所有请求返回后才更新数据, 且任何一个接口请求失败,就要阻止数据更新操作,那么Promise.all就用的上了。
它的参数是一个数组,每一项是一个promise值(就是所谓的resolve,其实就是一个值,或者promise对象);
它的返回值是一个 promise_resolve的数组
const p_1 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve('p1')}),2000});const p_2 = Promise.resolve('p2');const p_3 = Promise.resolve({then:(resolve)=>{resolve('p3');}});const p_4 = 'p4';Promise.all([p_1,p_2,p_3,p_4]).then(console.log) // 打印 ["p1", "p2", "p3", "p4"].catch(console.log)// 当某一个发生errorconst p_5 = Promise.resolve({then: (resolve,reject)=>{throw new Error('p_5error');resolve('p_5');}})const p_6 = Promise.resolve({then: (resolve,reject)=>{reject('p_6error');resolve('p_6')}})Promise.all([p_2,p_5]).then(console.log) //不会执行这句.catch(console.log) // ErrorPromise.all([p_2,p_6]).then(console.log) //不会执行这句.catch(console.log) // p_6error
当然,正是由于Promise.all这样的设计,所以某些场景下(与上述的场景要求不同)它反而会起不好的作用:
比如 我们的页面组件 需要同时发送多个请求,如果用promise.all 的话,有一个请求失败 那么所有后续操作(
就是Promise.all之后的.then )都会挂掉。
Promise.race
Promise.race 正如其名,race(赛跑)。
它的参数与Promise.all是一致的 => 都是一个resolve值组成的数组;
它的返回值是数组中最快的那个返回的promise对象
const p1 = new Promise((resolve)=>{resolve('p1')});const p2 = 'p2';const p3 = Promise.resolve('p3');Promise.race([p1,p2,p3]).then(console.log) // p1 因为都不是异步,顺序执行,p1最先const p4 = new Promise((resolve)=>{setTimeout(()=>{resolve('p4')})})Promise.race([p4,p2]).then(console.log) // p2 因为p2执行顺序优先const p5 = Promise.resolve({then:(resolve,reject)=>{reject('被catch的p5')}})Promise.race([p5,p4]).then(console.log).catch(console.log) // 被catch的p5
Promise的执行顺序
const p1 = new Promise(resolve=>{setTimeout(()=>{console.log('p1的函数执行了');resolve('p1的resolve值');},300)})const p2 = Promise.resolve('p2');setTimeout(()=>{console.log('这是一个0s的setTimeout')},0)const p3 = Promise.resolve({then:(resolve)=>{console.log('p3的thenable执行了')resolve('p3')}})const p4 = new Promise((resolve)=>{console.log('p4的函数执行');resolve('p4');})const p5 = new Promise((resolve)=>{setTimeout(()=>{console.log('p5的函数开始执行了');resolve('p5');})})Promise.race([p1]).then(value=>console.log(`[p1]的race结果: ${value}`))Promise.all([p1,p2,p3,p4]).then(console.log)Promise.race([p1,p2,p3,p4]).then(value=>console.log(`[p1,p2,p3,p4]的race结果: ${value}`))Promise.race([p1,p3]).then(value=>console.log(`[p1,p3]的race结果: ${value}`))Promise.race([p3,p4]).then(value=>console.log(`[p3,p4]的race结果: ${value}`))Promise.race([p4]).then(value=>console.log(`[p4]的race结果: ${value}`))p5.then(value=>console.log(`p5.then => ${value}`))p1.then((value)=>console.log(`p1.then => ${value}`));p3.then((value)=>console.log(`p3.then => ${value}`))//p4的函数执行// p3的thenable执行了// p3.then => p3//[p1,p2,p3,p4]的race结果: p2//[p3,p4]的race结果: p4//[p4]的race结果: p4//[p1,p3]的race结果: p3// 这是一个0s的setTimeout// p5的函数开始执行了// p5.then => p5// p1的函数执行了// p1.then => p1的resolve值// [p1]的race结果: p1的resolve值// ["p1的resolve值", "p2", "p3", "p4"]
封装Promise类
class MyPromise{constructor(fn){this.PromiseStatus = 'pedding';this._ProxyStatus = this.PromiseStatus;this.PromiseValue = undefined;this.resolvedCallbackList= [] ;this.failCllbackList = [];this.currentCall ={type: null,Index: -1}// this.promiseValue发生变化就执行这个;this.callThen = ()=> {if(!this.resolvedCallbackList.length){return null;}this.PromiseStatus = 'pedding';try{this.PromiseValue = this.resolvedCallbackList[0](this.PromiseValue);this.PromiseStatus = 'resolved';}catch(error){this.PromiseValue = error;this.PromiseStatus = 'fulfilled';}}this.then = (resolvedCallback) => {this.resolvedCallbackList.push(resolvedCallback);if(this.PromiseStatus==='resolved'){this.callThen();}return this;}this.catch = (failCallback) => {this.failCllbackList.push(failCallback);if(this.PromiseStatus==='fulfilled'){this.failCllbackList[0](this.PromiseValue);}return this;}Object.defineProperty(this,'PromiseStatus',{get: value => {return this._ProxyStatus;},set:(value)=>{this._ProxyStatus = value;if(value === 'resolved') {this.resolvedCallbackList.shift();this.callThen();}if(value === 'fulfilled') {this.failCllbackList[0]&&this.failCllbackList[0](this.PromiseValue);}}})try{this.resolvedCallbackList.push(fn);fn(value=>{this.PromiseValue = value;this.PromiseStatus = 'resolved';this.currentCall ={type: 'resolvedCallbackList',Index: 0}});}catch(error){this.PromiseValue = error;this.PromiseStatus = 'fulfilled';this.currentCall ={type: 'failCllbackList',Index: 0}}}}// 使用 1new MyPromise((resolve)=>{resolve(2);}).then(console.log)// 使用 2new MyPromise(resolve=>{setTimeout(()=>{console.log('setTimeOut执行');resolve(0);})}).then(value=>{console.log('第一个.then的callback')return value+1;}).then(value => {console.log('第二个.then');return value+1;}).then(console.log)// 使用 3 测试catch功能new MyPromise((resolve)=>{setTimeout(()=>{console.log('use3')resolve('44')},600)}).then(()=>{console.log('1then')}).then (()=>{throw new Error('这是一个error')}).then(()=>console.log('2then')).catch(console.log)
代码力的体现。
Promise的扩展学习
学习一个函数,我们需要从它的参数和返回值开始;
学习一个构造函数(类),还要学习它的实例挂载的属性和方法;
点击下面链接学习Promise:
es6Promise链接
