在需要多个操作的时候,会导致多个回调函数嵌套,导致代码不够直观,就是常说的回调地狱,通常通过promise来解决
Promise本意是承诺,在程序中的意思就是承诺我过一段时间后会给你一个结果。 什么时候会用到过一段时间?答案是异步操作,异步是指可能比较长时间才有结果的才做,例如网络请求、读取本地文件等
按照Promise/A+规范来实现一个Promise类
构造函数初始化逻辑
const PENDING = 'pending';//初始态
const FULFILLED = 'fulfilled';//初始态
const REJECTED = 'rejected';//初始态
let self = this;//先缓存当前promise实例
self.status = PENDING;//设置状态
self.onResolvedCallbacks = [];//定义存放成功的回调的数组
self.onRejectedCallbacks = []; //定义存放失败回调的数组
executor执行器,包含两个参数,分别是resolve 解决和reject 拒绝,new Promise这个executor就会执行
Promise有三个状态:初始化状态为pending,成功状态为fulfilled,失败状态rejected,如果代码一旦成功就不会走向失败,若 一直pending 永远不给你明确的答复
当调用以下方法的时候,如果promise状态为pending的话可以转成成功态,如果已经是成功态或者失败态了,则什么都不做
function resolve(value){
if(value!=null &&value.then&&typeof value.then == 'function'){
return value.then(resolve,reject);
}
setTimeout(function(){
if(self.status == PENDING){
self.status = FULFILLED;
self.value = value;
self.onResolvedCallbacks.forEach(cb=>cb(self.value));
}
})
}
function reject(reason){ //2.1.2
setTimeout(function(){
if(self.status == PENDING){
self.status = REJECTED;
self.value = reason;
self.onRejectedCallbacks.forEach(cb=>cb(self.value));
}
});
}
}
因为此函数执行可能会异常,所以需要捕获,如果出错了,需要用错误对象reject,如果这函数执行失败了,则用失败的原因reject这个promise,需要用try...catch(e)...进行处理
try{
executor(resolve,reject);
}catch(e){
reject(e);
};
Promise的解析过程
function resolvePromise(promise2,x,resolve,reject){
if(promise2 === x){
return reject(new TypeError('循环引用'));
}
let called = false;
if(x instanceof Promise){
if(x.status == PENDING){
x.then(function(y){
resolvePromise(promise2,y,resolve,reject);
},reject);
}else{
x.then(resolve,reject);
}
}else if(x!= null &&((typeof x=='object')||(typeof x == 'function'))){
try{
let then = x.then;
if(typeof then == 'function'){
then.call(x,function(y){
if(called)return;
called = true;
resolvePromise(promise2,y,resolve,reject)
},function(err){
if(called)return;
called = true;
reject(err);
});
}else{
resolve(x);
}
}catch(e){
if(called)return;
called = true;
reject(e);
}
}else{
resolve(x);
}
}
then
方法就是用来指定Promise 对象的状态改变时确定执行的操作,resolve 时执行第一个函数(onFulfilled),reject 时执行第二个函数(onRejected)
此方法中,如果成功和失败的回调没有传,则表示这个then没有任何逻辑,只会把值往后抛
Promise.prototype.then = function(onFulfilled,onRejected){
onFulfilled = typeof onFulfilled == 'function'?onFulfilled:function(value){return value};
onRejected = typeof onRejected == 'function'?onRejected:reason=>{throw reason};
let self = this;
let promise2;
if(self.status == FULFILLED){
return promise2 = new Promise(function(resolve,reject){
setTimeout(function(){
try{
let x =onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
})
});
}
if(self.status == REJECTED){
return promise2 = new Promise(function(resolve,reject){
setTimeout(function(){
try{
let x =onRejected(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
})
});
}
if(self.status == PENDING){
return promise2 = new Promise(function(resolve,reject){
self.onResolvedCallbacks.push(function(){
try{
let x =onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
});
self.onRejectedCallbacks.push(function(){
try{
let x =onRejected(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
});
});
}
}
promise的链式调用
- 每次调用返回的都是一个新的Promise实例
- 链式调用的参数通过返回值传递:即会将第一个then成功后,将他的返回值作为下一次成功的回调函数的参数
-
then
可以使用链式调用的写法原因在于,每一次执行该方法时总是会返回一个Promise
对象
catch
只是 promise.then(undefined, onRejected); 方法的一个别名而已。 也就是说,这个方法用来注册当promise对象状态变为Rejected时的回调函数
catch原理就是只传失败的回调
Promise.prototype.catch = function(onRejected){
this.then(null,onRejected);
}
Promise.all
接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用 .then 方法
Promise.all = function(promises){
return new Promise(function(resolve,reject){
let done = gen(promises.length,resolve);
for(let i=0;i<promises.length;i++){
promises[i].then(function(data){
done(i,data);
},reject);
}
});
}
Promise.race
只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理
Promise.race = function(promises){
return new Promise(function(resolve,reject){
for(let i=0;i<promises.length;i++){
promises[i].then(resolve,reject);
}
});
}
别人提供 给你一个方法,需要你传入一个promise,但你只有一个普通的值,你就可以通过这个方法把这个普通的值(string number object)转成一个promise对象
返回一个立刻成功的promise
Promise.resolve = function(value){
return new Promise(function(resolve){
resolve(value);
});
}
返回一个立刻失败的promise
Promise.reject = function(reason){
return new Promise(function(resolve,reject){
reject(reason);
});
}