手写Promise A+
Promise 是异步编程的一种解决方案。ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise对象有以下两个特点:
- 对象的状态不受外界影响
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。
基础实现Promise
function Promise(cb){
let self = this;
this.status = 'PENDING';//promise的状态 默认pending
this.value = null;//promise的值
this.onResolvedCallback = [];//成功的回调函数
this.onRejectedCallback = [];//失败的回调函数
function resolve(value){
setTimeout(() => {
self.value = value;
//promise的状态变为resolved 之后,遍历调用成功回调函数
self.onResolvedCallback.forEach(cb => {
cb(self.value)
})
})
}
function reject(value){
setTimeout(() => {
self.value = value;
//promise的状态变为rejected 之后,遍历调用成功回调函数
self.onRejectedCallback.forEach(cb => {
cb(self.value)
})
})
}
}
在上面的代码中,我们建立一个Promise函数,在函数中添加了Promise的返回值value、成功的回调函数队列onResolvedCallback、失败的函数回调队列onRejectedCallback。
然后编写了函数的resolve、reject方法,在方法中使用setTimeout来实现异步。方法都接受一个参数,表示当Promise状态变为resolved、rejected时返回值。最后,遍历对应的回调队列,触发队列中的每一个回调函数,并且将value传入。
then
then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
Promise.prototype.then = function(onResolved,onRejected){
//避免传入的不是函数
onFulfilled =
typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected =
typeof onRejected === 'function'
? onRejected
: error => {
throw error
}
//缓存this上下文对象 在哪个promise中调用,指向谁
let self = this;
return new Promise((resolve,reject) => {
if(self.status === 'RESOLVED'){//成功
self.onResolvedCallback.push(function(){
//调用成功回调 获取结果
let result = onResolved(self.value);
//如果返回值为新的promise对象 则继续调用then
if(result instanceof Promise){
result.then(resolve,reject);
}else {
//否则直接resolve
resolve(result)
}
})
}else if(self.status === 'REJECTED'){
self.onRejectedCallback.push(function(){
//调用回调 获取结果
let result = onRejected(self.value);
//如果返回值为新的promise对象 则继续调用then
if(result instanceof Promise){
result.then(resolve,reject);
}else {
//否则直接resolve
reject(result)
}
})
}else if (self.status === 'PENDING') {
self.onResolvedCallback.push(function() {
let result = onResolved(self.value)
if (result instanceof Promise) {
result.then(resolve, reject)
} else {
resolve(result)
}
})
self.onRejectedCallback.push(function(){
let result = onRejected(self.value);
if(result instanceof Promise){
result.then(resolve,reject)
}else {
reject(result)
}
})
}
})
}
在then函数中,我们需要保存调用then函数时的上下文对象,然后根据此时promise的状态,分别进行不同的处理。
all
promise.all(),具有以下特性:
- 接收一个
_Promise_实例的数组或具有_Iterator_接口的对象, - 如果元素不是
_Promise_对象,则使用_Promise.resolve_转成_Promise_对象 - 如果全部成功,状态变为
_resolved_,返回值将组成一个数组传给回调 - 只要有一个失败,状态就变为
_rejected_,返回值将直接传递给回调_all() _的返回值也是新的_Promise_对象
Promisre.prototype.all = function(promises){
return new Promise((resolve,reject) => {
if(!Array.isArray(promises)){
return reject(new TypeError('arguments must be an array'))
}
let count = 0,
len= promises.length,
resolveValues = new Array(len);
for (let i = 0; i < len; i++) {
promises[i].then((value) => {
count++;
resolveValues[i] = value;
if(count === len){
return resolve(resolveValues)
}
},(value) => {
return reject(value)
})
}
})
}
catch
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
}
Promsie.resolve
实现一个Promise.resolve()方法,要注意以下几点:
- 参数为
Promise实例,直接返回该实例 - 参数为一个
thenable对象,Promise.resolve()方法会将这个对象转为Promise对象,然后就立即执行thenable对象的then方法。 - 参数不是具有
then方法的对象,或根本就不是对象,则返回一个新的Promise对象,状态为resolve - 不带有任何参数,直接返回一个新的
promise对象,状态为resolved。
Promise.prototype.resolve = function(params){
if(params instanceof Promise){
return params
}
return new Promise((resolve,reject) => {
if(params && prams.then && typeof params.then === 'fuunction'){
params.then(resolve,reject)
}else {
resolve(params)
}
})
}
Promise.reject
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
Promise.prototype.reject = function(reason){
return new Promise((resolve,reject) => {
reject(reason)
})
}
ok,这样我们的promise A+基本就简单实现了。