1、基础版promise的实现
// 1.promise是一个类
// 2.当使用promise的时候 会传入一个执行器,此执行器是立即执行
// 3.当前executor 给了两个函数可以来描述当前promise的状态。promise中有三个状态 成功态 失败态 等待态
// 默认为等待态 如果调用resolve会走到成功态,如果调用reject 或者发生异常 会走失败态
// 4.每个promise实例都有一个then方法
// 5.promise 一旦状态变化后不能更改
const PENDING = 'PENGING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
class Promise {
constructor(executor) {
this.status = PENDING
this.value = undefined // 成功结果
this.reason = undefined // 失败原因
const resolve = (value) => {
if (this.status === PENDING) { // 只有在状态为pending的时候才能够修改状态
this.status = FULFILLED
this.value = value
}
}
const reject = (reason) => {
if (this.status === PENDING) { // 只有在状态为pending的时候才能够修改状态
this.status = REJECTED
this.reason = reason
}
}
try {
executor(resolve,reject) // promise 有两个参数 分别为成功的执行函数 和失败的执行函数
} catch (error) {
reject(error) // 针对执行器立即执行的时候抛出错误
}
}
then(onFulfilled,onRejected) {
if (this.status === FULFILLED){ // 执行成功回调
onFulfilled(this.value)
}
if (this.status === REJECTED) { // 执行失败回调
onRejected(this.reason)
}
}
}
module.exports = Promise
2、promise的异步处理
针对场景:
let promise = new Promise((resolve,reject)=>{ // pending
setTimeout(() => {
resolve('ok')
}, 1000);
})
// 当用户调用then方法的时候 此时promise可能为等待态, 先暂存起来,因为后续可能会调用resolve和reject, 等会再触发对应onFulfilled 或者 onRejected
promise.then((value)=>{ // then是异步的
console.log('success1',value)
},(reason)=>{
console.log('err',reason)
})
利用发布订阅将回调函数暂存 最后执行
const PENDING = 'PENGING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
class Promise {
constructor(executor) {
this.status = PENDING
this.value = undefined // 成功结果
this.reason = undefined // 失败原因
this.onResolvedCallbacks = [] // 存储成功的回调函数
this.onRejectedCallbacks = [] // 存储失败的回调函数
const resolve = (value) => {
if (this.status === PENDING) { // 只有在状态为pending的时候才能够修改状态
this.status = FULFILLED
this.value = value
// 发布
this.onResolvedCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.status === PENDING) { // 只有在状态为pending的时候才能够修改状态
this.status = REJECTED
this.reason = reason
// 发布
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve,reject) // promise 有两个参数 分别为成功的执行函数 和失败的执行函数
} catch (error) {
reject(error) // 针对执行器立即执行的时候抛出错误
}
}
then(onFulfilled,onRejected) {
// 订阅
if (this.status === PENDING){ // 在pending状态的时候收集成功回调/失败回调 利用切片编程(AOP)实现成功/失败回调函数的可扩展性
this.onResolvedCallbacks.push(()=> {
// 此处可以增加自定义逻辑
onFulfilled(this.value)
})
this.onRejectedCallbacks.push(()=> {
// 此处可以增加自定义逻辑
onRejected(this.reason)
})
}
if (this.status === FULFILLED){ // 执行成功回调
onFulfilled(this.value)
}
if (this.status === REJECTED) { // 执行失败回调
onRejected(this.reason)
}
}
}
module.exports = Promise
3、promise的链式调用
当调用.then方法之后回返回一个新的promise
分析then方法的返回值
情况1: then中方法返回的是一个(普通值 不是promise)的情况, 会作为外层下一次then的成功结果
情况2: then中方法 执行出错 会走到外层下一次then的失败结果
清空3: 如果then中方法返回的是一个promise对象, 此时会根据promise的结果来处理是走成功还是失败 (传入的是成功或者失败的内容)
无论上一次then走是成功还是失败,只要返回的是普通值 都会执行下一次then的成功 如果返回一个失败的promise或者抛出异常,会走下一个then的失败
// 利用x的值来判断是调用promise2的resolve还是reject
function resolvePromise (promise2,x,resolve,reject) {
// 第一种情况 如果返回的x和promise2相同 直接抛异常
if (promise2 === x) {
return reject(new TypeError('错误'))
}
// 判断返回的是不是对象或者函数 只有返回的是对象或者函数才有可能是promise
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
// 兼容其他的promise 避免重复调用出现异常
let called = false
// 通过.then方法判断是不是promise 由于.then的时候可能出现异常
try {
let then = x.then
// 如果then是一个函数 则认为是promise
if (typeof then === 'function') {
// 此处不建议直接使用x.then 这样写同样会触发getter可能会发生异常
then.call(x,(y) => {
if (called) return
called = true
resolvePromise(promise2,x,resolve,reject) // 一直解析到不是promise为止
}, (r) => {
if (called) return
called = true
reject(r)
})
} else {
// then不是函数 直接调用resolve
resolve(x)
}
} catch (error) {
if (called) return
called = true
reject(error)
}
} else {
// 既不是对象也不是函数则为普通值 直接调用resolve
resolve(x)
}
}
const PENDING = 'PENGING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
class Promise {
constructor(executor) {
this.status = PENDING
this.value = undefined // 成功结果
this.reason = undefined // 失败原因
this.onResolvedCallbacks = [] // 存储成功的回调函数
this.onRejectedCallbacks = [] // 存储失败的回调函数
const resolve = (value) => {
if (this.status === PENDING) { // 只有在状态为pending的时候才能够修改状态
this.status = FULFILLED
this.value = value
// 发布
this.onResolvedCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.status === PENDING) { // 只有在状态为pending的时候才能够修改状态
this.status = REJECTED
this.reason = reason
// 发布
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve,reject) // promise 有两个参数 分别为成功的执行函数 和失败的执行函数
} catch (error) {
reject(error) // 针对执行器立即执行的时候抛出错误
}
}
// then参数是可选的
then(onFulfilled,onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }
// 针对链式调用的处理 需要返回一个新的promise
let promise2 = new Promise((resolve,reject) => {
// 将一下代码包裹在new Promise中 是因为需要拿到then方法的返回值 即 x
// 订阅
if (this.status === PENDING){ // 在pending状态的时候收集成功回调/失败回调 利用切片编程(AOP)实现成功/失败回调函数的可扩展性
this.onResolvedCallbacks.push(()=> {
setTimeout(() => { // 由于需要拿到promise2的值作为后续then方法的判断 同步执行会造成死循环
// 此处可以增加自定义逻辑
try { // 针对then方法中 抛出异常处理 throw new Error()
let x = onFulfilled(this.value) // x为成功回调的返回值
// 此x 可能是一个promise, 如果是promise需要看一下这个promise是成功还是失败 .then ,如果成功则把成功的结果 调用promise2的resolve传递进去,如果失败则同理
// x的值是决定调用promise2的成功还是失败 如果是promise则取它的状态 如果是普通值 则直接调用resolve
resolvePromise(promise2,x,resolve,reject)
} catch (error) { // 如果then方法中抛出异常 直接走到下一个then的reject中
reject(error)
}
}, 0);
})
this.onRejectedCallbacks.push(()=> {
setTimeout(() => {
// 此处可以增加自定义逻辑
try { // 针对then方法中 抛出异常处理 throw new Error()
let x = onRejected(this.reason) // x为失败回调的返回值
resolvePromise(promise2,x,resolve,reject)
} catch (error) { // 如果then方法中抛出异常 直接走到下一个then的reject中
reject(error)
}
}, 0);
})
}
if (this.status === FULFILLED){ // 执行成功回调
setTimeout(() => {
try { // 针对then方法中 抛出异常处理 throw new Error()
let x = onFulfilled(this.value) // x为成功回调的返回值
resolvePromise(promise2,x,resolve,reject)
} catch (error) { // 如果then方法中抛出异常 直接走到下一个then的reject中
reject(error)
}
}, 0);
}
if (this.status === REJECTED) { // 执行失败回调
setTimeout(() => {
try { // 针对then方法中 抛出异常处理 throw new Error()
let x = onRejected(this.reason) // x为失败回调的返回值
resolvePromise(promise2,x,resolve,reject)
} catch (error) { // 如果then方法中抛出异常 直接走到下一个then的reject中
reject(error)
}
}, 0);
}
})
return promise2
// 此处不能直接return this this是当前的promise 返回的必须是一个新的promise 如果是当前的promise promise的状态是一旦改变便无法再次更改的
}
}
module.exports = Promise
测试promise
安装测试插件
npm install promises-aplus-tests -g
添加一下测试代码
Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve= resolve;
dfd.reject = reject;
});
return dfd;
}
命令行执行命令promises-aplus-tests xxx.js
4、promise的方法
static resolve(value) {
return new Promise((resolve,reject) => {
resolve(value)
})
}
static reject(reason) {
return new Promise((resolve,reject) => {
reject(reason)
})
}
static all (promises) {
return new Promise((resolve,reject) => {
let result = []
let times = 0
const processSuccess = (index,val) => {
result[index] = val
if (++times === promises.length) {
resolve(result)
}
}
// 遍历所有传入的promise
for(let i = 0; i < promises.length; i++) {
let p = promises[i] // 获取传入的某一个参数
// 判断传入的是promise还是普通值
if (p && typeof p.then === 'function') {
p.then((value) => {
processSuccess(i,value)
}, reject)
} else {
// 如果是普通值 直接传入
processSuccess(i,p)
}
}
})
}
// race 方法如果其中一个完成了 其他的还是会执行的,并没有采用他的结果
static race (promises) {
return new Promise((resolve,reject) => {
for(let i = 0; i < promises.length; i++) {
let p = promises[i]
if (p && typeof p.then === 'function') {
p.then(resolve,reject) // 一旦成功就直接 停止
} else {
resolve(p)
}
}
})
}
catch(errorCallbackFn) {
return this.then(null, errorCallbackFn)
}
finally (cb){
return this.then((data) => {
return Promise.resolve(cb()).then(n => {
return data
})
},err=> {
return Promise.resolve(cb()).then(n => {
throw err
})
})
}
promisify和promisifyAll
promisify 主要的功能是将一个异步的方法转化成promise的形式 主要是给node来使用的
回调函数的参数 永远第一个是error
function promisify(fn) {
return function (...args) {
return new Promise((resolve,reject) => {
fn(...args, (err,data) => {
if (err) return reject(err)
resolve(data)
})
})
}
}
function promisifyAll(obj) {
let o = {}
for(let key in obj) {
if (typeof obj[key] === 'function') {
o[key + 'Promise'] = promisify(obj[key])
}
}
return o
}