Promise
由于js的语言特性(用户交互)和工作环境(浏览器脚本),决定了它是单线程工作,所以两段脚本不能同时运行,但为了实现功能,所以人们使用了事件和回调来初步解决这个问题,例如(addEventListener),但这也带来了严重的回调问题,非常容易陷入回调地狱的困恼,
由于这个问题。js发展至今,社区提出了promise(承若)标准,被es6写入了语言标准中,统一了它的用法,并在原生中提供了标准的Promise对象
让我们先来实例化一个标准的promise对象:
//实例化一个promise对象,这个对象有两个参数(resolve-决定,reject-拒绝)
let promise = new Promise((resolve,reject)=>{
//延时3s,把promise的状态改为resolve-决定
setTimeout(function(){
resolve('666')
},3000)
})
//每个实例都有then()方法,用来获取其值或原因。
//then(onFulfilled, onRejected)
//成功的回调,失败的回调
promise.then(data=>{
console.log(data)
},err=>{
console.error(err)
}).then()
同时promise还可以多次调用then()方法,也可以在resolve中继续抛出一个新的promise 例:
promise.then(function(data){
console.log('data2=',data);
},function(err){
console.log('err2=',err);
});
或者:
let promise2 = promise.then(function(data){
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve(data + '777' );
},1000);
});
});
当然还有常见的all(),catch(),resolve(),reject()等等一些方法,而这些方法都是按照Promise/A+规范规定的 (详情)
我们现在就按照这个规范来实现一个属于我们自己的promise
首先我们先定义出这个类:
// executor是一个执行函数,在实例化的时候被传入。这个函数会执行两个被传入的状态函数
var Promise = function (executor) {
let self = this;
//没个promise都会有个初始化值,这个值在规范中叫做pending
self.status = 'pending';
self.value = undefined; // 默认成功的值
self.reason = undefined; // 默认失败的原因
self.onResolvedCallbacks = []; // 存放then成功的回调
self.onRejectedCallbacks = []; // 存放then失败的回调
// 成功状态要执行的函数
function resolve(value) {
//更改他的状态值,为成功,且不能更改
if (self.status === 'pending') {
self.status = 'resolved';
self.value = value;
//实例多次调用then(),循环释放数组
self.onResolvedCallbacks.forEach(function (fn) {
fn();
});
}
}
// 失败状态要执行的函数
function reject(reason) {
//更改他的状态值,为失败,且不能更改
if (self.status === 'pending') {
self.status = 'rejected';
self.reason = reason;
//实例多次调用then(),循环释放数组
self.onRejectedCallbacks.forEach(function (fn) {
fn();
})
}
}
如果直接传入错误的代码,那么直接进入reject
try {
executor(resolve, reject)
} catch (e) {
// 捕获的时候发生异常,就直接失败了
reject(e);
}
}
下面我们来实现then()方法,个方法每个实例都有,他是一个方法,所以我们把它挂载到Promise原型上:
Promise.prototype.then = function (onFulfilled, onRjected) {
//成功和失败默认一个函数,防止报错,
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
return value;
}
onRjected = typeof onRjected === 'function' ? onRjected : function (err) {
throw err;
}
let self = this;
//定义一个返回的promise
let promise2;
//当状态是成功的时候,可能会在函数中再次返回一个promise
if (self.status === 'resolved') {
promise2 = new Promise(function (resolve, reject) {
// 当成功或者失败执行时有异常那么返回的promise应该处于失败状态
//这个x 是第一个promise执行后的结果
// x可能是一个promise 也有可能是一个普通的值
setTimeout(function () {
try {
let x = onFulfilled(self.value);
// x可能是别人promise,写一个方法统一处理
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
})
}
//当状态是失败的时候
if (self.status === 'rejected') {
promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
try {
let x = onRjected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
})
}
// 当调用then时可能没成功 也没失败
if (self.status === 'pending') {
promise2 = new Promise(function (resolve, reject) {
// 此时没有resolve 也没有reject
self.onResolvedCallbacks.push(function () {
setTimeout(function () {
try {
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
})
});
self.onRejectedCallbacks.push(function () {
setTimeout(function () {
try {
let x = onRjected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
});
})
}
return promise2;
}
集中处理x
function resolvePromise(promise2, x, resolve, reject) {
// 有可能这里返回的x是别人的promise
// 先跑错
if (promise2 === x) { //这里应该报一个类型错误,有问题
return reject(new TypeError('循环引用了'))
}
// 看x是不是一个promise,promise应该是一个对象
let called; // 表示是否调用过成功或者失败
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
//根据语法规定的几种情况来判断
// 可能是promise {},看这个对象中是否有then方法,如果有then我就认为他是promise了
try {
let then = x.then;
if (typeof then === 'function') {
// 成功
then.call(x, function (y) {
if (called) return
called = true
// y可能还是一个promise,在去解析直到返回的是一个普通值
//递归调用这个函数,
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 { // 说明是一个普通值1
resolve(x); // 表示成功了
}
}
在实现了这些之后,其他的方法,更多的就是一个语法糖,我们来实现他们
catch:
扫描二维码关注公众号,回复:
5602458 查看本文章
catch实际上就是reject,所以一般建议在then里面不穿reject(),而链式调用catch方法
Promise.prototype.catch = function (callback) {
return this.then(null, callback)
}
all
//会传入一个数组,这个数组是promise集合
Promise.all = function (promises) {
return new Promise(function (resolve, reject) {
//arr是最终返回值的结果
let arr = [];
// 表示成功了多少次
let i = 0;
function processData(index, y) {
arr[index] = y;
if (++i === promises.length) {
resolve(arr);
}
}
for (let i = 0; i < promises.length; i++) {
promises[i].then(function (y) {
processData(i, y)
}, reject)
}
})
}
race
//race就是赛跑的意思,谁获取结果比较快,就返回谁
// 只要有一个promise成功了 就算成功。如果第一个失败了就失败了
Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
for (var i = 0; i < promises.length; i++) {
promises[i].then(resolve,reject)
}
})
}
// 生成一个成功的promise
Promise.resolve = function(value){
return new Promise(function(resolve,reject){
resolve(value);
})
}
// 生成一个失败的promise
Promise.reject = function(reason){
return new Promise(function(resolve,reject){
reject(reason);
})
}
defer 延期处理
会包容promise 可用于封装在传递方法之外调用原有的promise回调
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise(function (resolve, reject) {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd
}