基于PromiseA+实现
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
// 定义解析promise返回值是不是Promise做处理的方法(链式调用实现)
const resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('[TypeError: 循环引用!]'))
}
// 1. 正常情况我们要分析x是不是 promise, 如果x是普通值就直接resolve就行
// 2. 判断x是不是promise, 不能用instanceof 因为别人的promise和自己的没法instanceof(promise可以和其他人写的互相调用)
// 3. 只有x 是函数或对象是才有可能是一个promise
if ((typeof x === 'object' && x !== null) || (typeof x === 'function')) {
let called = false; // 标记防止别人的promise即调成功, 又调失败, 或者多次调用
try {
let then = x.then;
if (typeof then.call(x) === 'function') {
then.call(x, function(y) {
if (called) return;
// 可能又返回了promise,所以要递归解析直到是普通值为止
called = true;
resolvePromise(promise2, y, resolve, reject)
}, function(r) {
if (called) return;
called = true;
reject(r)
})
} else {
resolve(x) // then就是一个对象
}
} catch(e) {
if (called) return;
called = true;
reject(e) // 取then的时候抛错了
}
} else {
resolve(x) // 普通值直接结束
}
};
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reson = undefined;
// 异步的时候需要把调用存起来,等状态变为非pending时再执行
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
// 用户调用的成功和失败
const resolve = (value) => {
// 实现直接resolve一个promise的情况 Promise.resolve(new Promise()) // 里面是普通值没有问题,是Promise就需要如下处理
if (value instanceof Promise) {
return value.then(resolve, reject)
}
// 状态只能改变一次
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
this.onResolvedCallbacks.forEach(fn => fn());
}
}
const reject = (reson) => {
if (this.status === PENDING) {
this.reson = reson;
this.status = REJECTED;
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
// 立即执行
executor(resolve, reject)
} catch(e) {
reject(e)
}
};
then(onFulfilled, onRejected) {
// 给默认值 如果调then没传成功和失败函数,要给默认值,一直传到有处理的地方 then().then().then(() => {}, () => {})
onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : v => v;
onRejected = typeof onRejected == 'function' ? onRejected : err => { throw err };
let promise2 = new Peomise((resolve, reject) => {
// 同步处理
if (this.status === FULFILLED) {
setTimeout(() => {
try {
// 根据第一个promise的then返回值决定下一个promise调用成功还是失败
let x = onFulfilled(this.value);
// 这里需要判断返回值是不是promise
// promise2这时候还没创建出来,所以这里的代码要用异步执行包裹
resolvePromise(promise2, x, resolve, reject)
} cacth(e) {
reject(e)
}
})
};
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reson)
resolvePromise(promise2, x, resolve, reject)
} cacth(e) {
reject(e)
}
})
}
// 异步处理
if (this.status === PENDING) {
// 订阅 push包一层是为了可扩展, 可以拿到函数的返回值
this.onResolvedCallback.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value) // 调用的时候就是非pending状态有value了
resolvePromise(promise2, x, resolve, reject)
} cacth(e) {
reject(e)
}
})
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reson)
resolvePromise(promise2, x, resolve, reject)
} cacth(e) {
reject(e)
}
})
});
}
})
}
// catch 的本质就是then
catch(errCallback) {
return this.then(null, errCallback)
}
// 无论成功还是失败都执行
finally(fn) {
return this.then(
(data) => Promise.resolve(fn()).then(() => data),
(err) => Promise.resolve(fn()).then((err) => { throw err })
)
}
// Promise.resolve 会等待内部的promise执行完毕
static resolve(value) {
return new Promise((resolve, reject) => {
resolve(value)
})
}
// Promise.reject 不会等待内部的promise执行完毕
static reject(reson) {
return new Promise((resolve, reject) => {
reject(reson)
})
}
// 全部成功才成功, 有一个失败就失败, 成功结果与调用顺序一致
static all(values) {
let ret = [] // 最终的结果
let len = values.length;
return new Promise((resolve, reject) => {
values.forEach((val, idx) => {
// 兼容val不是promise的情况也给包装成promise
Promise.resolve(val).then(data => {
ret[idx] = data;
if (--len === 0) resolve(ret)
}, reject) // 任何一个promise失败, 直接调用最外层的返回
})
})
}
// 赛跑 谁快用谁的结果 一个成功就成功, 一个失败就失败 使用场景: 处理超时 比如500毫秒之后调某个promise接口的reject就走到失败
static race(values) {
return new Promise((resolve, reject) => {
values.forEach((val, idx) => {
Promise.resolve(val).then(resolv, reject)
})
})
}
// 只要其中的一个promise成功,就返回那个已经成功的, 全部都失败就返回一个失败的promise和aggregateError类型的实例
static any(values) {
const reasons = []
return new Promise((resolve, reject) => {
values.forEach(val => {
val.then(resolve, err => {
reasons.push(err)
if (reasons.length === values.length) {
reject(new AggregateError(reasons))
}
})
})
})
}
// 不会失败, 数组里的promise实例全部改变状态就成功, 成功返回promise实例都改变的数组[{status:’ fullfilled’,value},{status:’ fullfilled’,value},{status:’ fullfilled’,value}]
static allSettled(values) {
return new Promise((resolve) => {
const ret = [];
let len = values.length;
values.forEach(val => {
val.then(res => {
ret.push({ status: FULFILLED, value: res})
if (--len === 0) {
resolve(results)
}
}, err => {
ret.push({ status: REJECTED, value: err})
if (--len === 0) {
resolve(ret)
}
})
})
})
}
};
module.export = Promise;
简单使用
const Promise = require('./promise');
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 1000)
})
promise.then(value => { // 订阅
console.log('成功', value)
}, reson => {
console.log('失败', reson)
})
// 多次调用
promise.then(value => {
console.log('成功', value)
}, reson => {
console.log('失败', reson)
})
链式调用使用
// 读取两个文件内容的异步场景
const fs = require('fs');
const path = require('path');
// 异步方法先变成promise
function readFile(url) {
return new Promise((resolve, reject) => {
fs.readFile(path.resolve(__dirname, url), 'utf8', function(err,data) {
if(err) {
return reject(err)
}
resolve(data)
})
})
}
// 1. 如果一个promise.then中的方法 返回的是一个peomise, 那么就会自动解析返回的promise,采用它的状态作为下一次then的结果
// 2. 如果then中的方法, 返回的不是promise, 则会直接走下一次的then的成功
// 3. then中的方法抛出异常, 走下一次then的失败
// 什么时候会让promise.then走失败?
// a) 返回失败的promise
// b) 抛出异常
// promise实现链式调用采用的是每次调用then方法都返回一个全新的prmise, 为什么不return this ? (如果一直是同一个promise, promise不能从成功变为失败)
readFile('fileUrl.txt').then((data) => {
// 又返回一个promise, 成功走下一次成功,失败走下一次失败
return readFile(data);
}, (err) => {
console.log(err);
// 这里的失败返回结果只要不是promise就走下一次的成功
return undefined;
}).then((data) => {
console.log('下一次的then success' + data);
// 如果这里抛错了,则再走下一次then的失败
// throw new Error('出错了')
}, (err) => {
console.log('下一次的then fail' + err)
}).then((data) => {
console.log('上一次then成功并且返回promise成功或者失败返回值并且不抛错')
}, (err) => {
console.log(err, '上一次then抛错走这里')
})
promiseify实现
function promiseify(fn) { // fs.readFile 实现一个文件读取的promiseify
return function (...args) {
return new Promise((resolve, reject) => {
fn(...args, function(err, data) {
if (err) return reject(err);
resolve(data)
})
})
}
}
// 使用
const readFile = promiseify(fs.readFile);
readFile(path.resolve(__dirname, 'note.txt'), 'utf8').then(data => console.log(data))
promiseifyAll实现
function promiseifyAll(obj) {
for(let key in obj) {
if (typeof obj[key] === 'function') {
obj[key] = promiseify(obj[key])
}
}
}
// 使用
promiseifyAll(fs); // 内部会识别对象上的所有方法 将属性依次promise化
fs.readFile(path.resolve(__dirname, 'note.txt'), 'utf8').then(data => console.log(data))