Promise是?
- es6之前,js解决异步的方案是 回调函数,这会带来一系列的问题,尤其是回调里嵌套回调导致的回调地狱;
如:
// 定义一个1s后执行callback的异步api
function 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 />上述看起来不好理解?没关系,看下面的代码:
```javascript
const promise = Promise.resolve(2);// 这个api接受一个值作为参数,返回的是一个promise对象
promise.then(value =>console.log(value));
//打印2 也就是说,上面的参数值会作为第一个.then的形参。 当然.then也会返回一个promise对象。
// 因此它们都可以链式调用
Promise.resolve(5)
.then(value=>{
console.log(value); //5
return value +1; // 返回值作为下一个.then的形参
})
.then(data=>console.log(data)) // 6
然后是关于 thenable参数的解读。 意思是如果传入的参数,含有.then的属性(它有可能是一个promise对象,也有可能是一个含有.then属性的普通对象),比如:
// 案例1
Promise.resolve({
then:(callback,failCallback)=>{
callback('嘿嘿')
}
}) // 传入了一个含有.then属性的对象
.then(console.log) // 嘿嘿
// 案例2
const 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)
// 当某一个发生error
const 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) // Error
Promise.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
}
}
}
}
// 使用 1
new MyPromise((resolve)=>{
resolve(2);
})
.then(console.log)
// 使用 2
new 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链接