Promise是什么
Promise是高版本浏览器自带的一个类,不兼容低版本浏览器。Promise对象有三个状态,等待态pending,成功态resolved,失败态rejected,默认为pending,成功或者失败后不可再变化状态。
我们为什么用Promise
在异步编程中可以帮助我们解决回调地狱的痛苦。方便有连带关系的异步请求编写,也可实现并发多个异步请求,同步异步的请求结果,还可以统一处理错误。
Promise如何使用
调用Promise时,传入一个excutor方法,其中包括两个参数,resolve、reject,excutor方法内部代码是同步的。每个Promise对象都有一个then方法,then接收两个函数,第一个是成功后执行的方法,第二个是失败后执行的方法,这两个方法都是异步的。前面说到excutor是同步的,那么下面代码结果是什么?为什么?
// promise 最基本用法
new Promise((resolve,reject)=>{
console.log(1);
resolve();
console.log(2);
}).then(()=>{
console.log('成功');
}, ()=>{
console.log('失败');
});
console.log(3);
// promise excutor中也可以使用异步 比如进行ajax封装等
new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve();
}, 0);
}).then(()=>{
console.log('成功');
}, ()=>{
console.log('失败');
});
// 方便的链式调用 后一个请求依赖前一个请求
let fs = require('fs');
function read(fileName){
return new Promise((resolve, reject)=>{
fs.readFile(fileName, 'utf8', (err, data)=>{
if (err) reject(err);
resolve(data);
})
});
}
// 逐个处理错误
// read('./1.txt').then((data)=>{
// return read(data);
// },(err)=>{
// console.log(1, err);
// }).then((data)=>{
// console.log('success', data);
// },(err)=>{
// console.log(2, err);
// });
// catch统一处理错误
read('./1.txt').then((data)=>{
return read(data);
}).then((data)=>{
console.log('success', data);
}).catch((err)=>{
console.log(err);
});
如果返回的的是Promise对象,那么此次的执行结果(成功或者失败),就会传递到下一个then方法中。如果是一个普通值或者undefined,就会走下一个then的成功。如果抛出异常就会走下一个then的失败,如果then什么也不传,直接传到下一个then的成功。那么看以下代码?结果是什么?
read('./1.txt').then((data)=>{
throw new Error('err');
}).then((data)=>{
console.log('age', data);
}).then().then(null, (err)=>{
// 直接穿透到后面then 执行第二个方法 这里捕获了错误 不会走后面的catch了
console.log('then', err);
}).catch((err)=>{
console.log('catch', err);
}).then((data)=>{
console.log(data);
});
new Promise((resolve, reject)=>{
resolve(1);
}).then((x)=>{
return x+1;
}).then((x)=>{
throw new Error(x);
}).catch(()=>{
return 1
}).then((x)=>{
return x+1
}).then((x)=>{
console.log(x);
}).catch((err)=>{
console.error(err);
})
new Promise((resolve,reject)=>{
resolve(1);
}).then((res)=>{
console.log(res);
return 2;
}).catch((err)=>3)
.then((res)=>{
console.log(res);
});
Promise处理并发 all方法返回的是一个promise对象
// Promise.all([1, 2, 3]).then((data)=>{
Promise.all([read('./1.txt'), read('./2.txt')]).then((data)=>{
// data是一个数组 按照请求时的顺序已排好
console.log(data);
}).catch((err)=>{
// 如果有一个失败 就会走catch
console.log(err);
});
自己实现一个Promise类
参考https://promisesaplus.com/,promiseA+规范。
// 基本版 Promise
class Promise{
constructor(excutor){
// status 为状态 默认pending 成功为fulfilled 失败为rejected
this.status = 'pending';
// 保存成功后的值
this.resolve = undefined;
// 保存失败的原因
this.reject = undefined;
let resolve = (value)=>{
// 只有pengding的时候才能修改状态
if(this.status === 'pending'){
this.status = 'fulfilled';
this.resolve = value;
}
};
let reject = (reason)=>{
// 只有pengding的时候才能修改状态
if(this.status === 'pending'){
this.status = 'rejected';
this.reject = reason;
}
};
// 如果excutor执行的时候出错了
try{
excutor(resolve, reject);
}catch(e){
reject(e);
}
}
then(onFulfilled, onReject){
if(this.status === 'fulfilled'){
onFulfilled(this.resolve);
}
if(this.status === 'rejected'){
onReject(this.reject);
}
}
}
let p = new Promise((resolve, reject)=>{
resolve(1);
});
p.then((value)=>{
console.log('v', value)
}, (err)=>{
console.log('err', err);
});
// 解决excutor中有异步代码 以及一个promise对象调用多个then方法的问题
class Promise{
constructor(excutor){
this.status = 'pending';
this.resolve = undefined;
this.reject = undefined;
this.onResolveCbs = [];
this.onRejectedCbs = [];
let resolve = (value)=>{
if(this.status == 'pending'){
this.status = 'fulfilled';
this.resolve = value;
// 成功 执行数组里的所有方法
this.onResolveCbs.forEach((item)=>item());
}
};
let reject = (reason)=>{
if(this.status == 'pending'){
this.status = 'rejected';
this.reject = reason;
this.onRejectedCbs.forEach((item)=>item());
}
};
try{
excutor(resolve, reject);
}catch(e){
}
}
then(onFulfilled, onReject){
// excutor 中有异步 把回调存起来 可能出现多个
if(this.status == 'pending'){
this.onResolveCbs.push(()=>{
onFulfilled(this.resolve);
});
this.onRejectedCbs.push(()=>{
onReject(this.reason);
});
}
if(this.status == 'fulfilled'){
onFulfilled(this.resolve);
}
if(this.status == 'rejected'){
onReject(this.reject);
}
}
}
let p = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve(1);
}, 1000);
});
p.then((value)=>{
console.log('v', value)
}, (err)=>{
console.log(err);
});
p.then((value)=>{
console.log('v', value)
}, (err)=>{
console.log(err);
});
// 解决链式调用
class Promise{
constructor(excutor){
this.status = 'pending';
this.resolve = undefined;
this.reject = undefined;
this.onResolveCbs = [];
this.onRejectedCbs = [];
let resolve = (value)=>{
if(this.status == 'pending'){
this.status = 'fulfilled';
this.resolve = value;
this.onResolveCbs.forEach((item)=>item());
}
};
let reject = (reason)=>{
if(this.status == 'pending'){
this.status = 'rejected';
this.reject = reason;
this.onRejectedCbs.forEach((item)=>item());
}
};
// 如果excutor执行的时候出错
try{
excutor(resolve, reject);
}catch(e){
reject(e);
}
}
then(onFulfilled, onReject){
// 链式调用
let promise2 = new Promise((resolve, reject)=>{
// excutor 中有异步 把回调存起来
if(this.status === 'pending'){
this.onResolveCbs.push(()=>{
// 加定时器 不然promise2为undefined
// try catch防止执行onFulfilled时出现异常
setTimeout(()=>{
try{
let x = onFulfilled(this.resolve);
resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e);
}
}, 0);
});
this.onRejectedCbs.push(()=>{
setTimeout(()=>{
try{
let x = onReject(this.reason);
resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e);
}
}, 0);
});
}else if(this.status === 'fulfilled'){
setTimeout(()=>{
try{
let x = onFulfilled(this.resolve);
resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e);
}
}, 0);
}else if(this.status === 'rejected'){
setTimeout(()=>{
try{
let x = onReject(this.reason);
resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e);
}
}, 0);
}
});
return promise2;
}
catch(onRejected){
return this.then(null, onRejected);
}
finally(cb){
return this.then((data)=>{
cb();
return data;
}, (err)=>{
cb();
throw err;
});
}
static race(promises){
return Promise((resolve, reject)=>{
for(let i = 0 ; i < promises.length; i++){
let promise = promises[i];
if(typeof promise.then == 'function'){
promise.then(resolve, reject);
}else{
resolve(promise);
}
}
});
}
static all(promises){
return new Promise((resolve, reject)=>{
let arr = [],
i = 0;
let processData = (index, data)=>{
arr[index] = data;
if(++index == promises.length){
resolve(arr);
}
};
for(let i = 0; i < promises.length; i++){
let promise = promises[i];
if(typeof promise.then == 'function'){
promise.then((data)=>{
processData(i, data);
}, reject);
}else{
processData(i, promise);
}
}
});
}
static resolve(data){
return new Promise((resolve, reject)=>{
resolve(data);
});
}
static reject(err){
return new Promise((resolve, reject)=>{
reject(err);
});
}
static deferred(){
let dfd = {};
dfd.promise = new Promise((resolve, reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
static defer(){
let dfd = {};
dfd.promise = new Promise((resolve, reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
}
function resolvePromise(promise2, x, resolve, reject){
if(promise2 == x)throw new TypeError('不能重复引用');
let called = false;
if(x && typeof x == 'object' || typeof x == 'function'){
try{
let then = x.then;
if(typeof then == 'function'){
then.call(x, (y)=>{
if(called)return;
called = true;
resolvePromise(x, y, resolve, reject);
}, (err)=>{
if(called)return;
called = true;
reject(err);
});
}else{
resolve(x);
}
}catch(e){
if(called)return;
called = true;
reject(e);
}
}else{
resolve(x);
}
}
let p = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve(1);
}, 1000)
});
p.then((value)=>{
// throw Error(value); // 这里抛出异常或者返回普通值 都没有问题
return value;
}, (err)=>{
console.log('1', err);
}).then((value)=>{
console.log('v', value)
}, (err)=>{
console.log('2', err);
});