先说下为什么要用promise? promise解决了哪些问题? 通常我们的回调都是放到回调函数中解决,会产生回调地狱问题,因此promise出现,解决了回调地狱问题。 promise不仅解决了回调地狱问题,还解决了统一错误处理
第一步简单实现
- 实现多次then及异步执行,so easy。
心得:resolve或reject方法的执行,只是改变promise的状态status和value值,很简单,不要多想。
const PENDING = 'PENDING'
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
class Promise{
constructor(executor){
this.value = ''
this.status = PENDING
this.onResolvedCallBacks = [] // 初始值为数组,executor为异步执行时,多次then会有多个函数存放
this.onRejectedCallBacks = []
const resolve = (value) => {
if (this.status === PENDING) {
this.value = value
this.status = RESOLVED
this.onResolvedCallBacks.forEach(fn => fn()) // 发布
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.value = reason
this.status = REJECTED
this.onRejectedCallBacks.forEach(fn => fn()) // 发布
}
}
try {
executor(resolve,reject)
}catch(e){
reject(e)
}
}
then(onFulfilled, onRejected) {
if (this.status === RESOLVED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejected(this.value)
}
if (this.status === PENDING) { // 订阅
this.onResolvedCallBacks.push(() => { // 函数中方便处理, 装饰模式,切片编程
onFullfilled(this.value)
})
this.onRejectedCallBacks.push(() => {
onRejected(this.value)
})
}
}
}
module.exports = Promise
- 测试一下
1) 测试异步执行
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000);
}).then(value => {
console.log(value)
})
// 1
2) 测试多次then
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000);
})
promise.then(value => {
console.log('value1: ', value)
})
promise.then(value => {
console.log('value2: ', value)
})
// value1: 1
// value2: 1
第二步then的链式调用实现
- 实现then的链式调用(主要靠then回调方法的返回值)
const PENDING = 'PENDING'
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
// 可以看做,此方法主要处理promise2的状态
// then参数方法为一个promise, 通过方法的返回值,来判断下个then的执行
function resolvePromise(x, promise2, resolve, reject) {
if (x === promise2) {
reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// 判断x 来执行resolve或reject
// 判断x是否为promise:是object类型、有then方法且类型为function
if (typeof x === 'object' && x !== null || typeof x === 'function') {
try {
let then = x.then
if (typeof then === 'function') {
// x为promise
then.call(x, y => {
resolvePromise(y, promise2, resolve, reject)
}, r => {
reject(r)
})
} else {
// {then: 1}
resolve(x)
}
}catch(e) {
// {then: throw new Error('err')}
reject(e)
}
} else {
// x为普通值
resolve(x)
}
}
class Promise{
constructor(executor){
this.value = ''
this.status = PENDING
this.onResolvedCallBacks = [] // 初始值为数组,executor为异步执行时,多次then会有多个函数存放
this.onRejectedCallBacks = []
const resolve = (value) => {
if (this.status === PENDING) {
this.value = value
this.status = RESOLVED
this.onResolvedCallBacks.forEach(fn => fn()) // 发布
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.value = reason
this.status = REJECTED
this.onRejectedCallBacks.forEach(fn => fn()) // 发布
}
}
try {
executor(resolve,reject)
}catch(e){
reject(e)
}
}
then(onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {
if (this.status === RESOLVED) {
setTimeout(() => {
try {
// 重点
let x = onFulfilled(this.value)
resolvePromise(x, promise2, resolve, reject)
}catch(e) {
reject(e)
}
}, 0)
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
// 重点
let x = onRejected(this.value)
resolvePromise(x, promise2, resolve, reject)
}catch(e) {
reject(e)
}
}, 0)
}
if (this.status === PENDING) { // 订阅
this.onResolvedCallBacks.push(() => { // 函数中方便处理
setTimeout(() => {
try {
// 重点
let x = onFulfilled(this.value)
resolvePromise(x, promise2, resolve, reject)
}catch(e) {
reject(e)
}
}, 0)
})
this.onRejectedCallBacks.push(() => {
setTimeout(() => {
try {
// 重点
let x = onRejected(this.value)
resolvePromise(x, promise2, resolve, reject)
}catch(e) {
reject(e)
}
}, 0)
})
}
})
return promise2
}
}
module.exports = Promise
- 测试一下
new Promise((resolve, reject) => {
resolve(1)
}).then(value => {
console.log('value1: ', value)
return value
}).then(value => {
console.log('value2: ', value)
}, reason => {
console.log(reason)
})
// value1: 1
// value2: 1
第三步解决几个问题
- 1.值穿透
- 2.解决resolve的value为Promise的情况
- 3.解决引入其他不规范的promise,导致多次调用问题
const PENDING = 'PENDING'
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
function resolvePromise(x, promise2, resolve, reject) {
if (x === promise2) {
reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// 判断x 来执行resolve或reject
// 判断x是否为promise:是object类型、有then方法且类型为function
if (typeof x === 'object' && x !== null || typeof x === 'function') {
let called; // 解决问题3
try {
let then = x.then
if (typeof then === 'function') {
// x为promise
then.call(x, y => {
if(called)return
called = true
resolvePromise(y, promise2, resolve, reject)
}, r => {
if(called)return
called = true
reject(r)
})
} else {
// {then: 1}
resolve(x)
}
} catch(e) {
// {then: throw new Error('err')}
if(called)return
called = true
reject(e)
}
} else {
// x为普通值
resolve(x)
}
}
class Promise{
constructor(executor){
this.value = ''
this.status = PENDING
this.onResolvedCallBacks = [] // 初始值为数组,executor为异步执行时,多次then会有多个函数存放
this.onRejectedCallBacks = []
const resolve = (value) => {
if (this.status === PENDING) {
// 如果value为Promise的实例,则递归解析出this.value,解决问题2
if (value instanceof Promise) {
return value.then(resolve, reject)
}
this.value = value
this.status = RESOLVED
this.onResolvedCallBacks.forEach(fn => fn()) // 发布
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.value = reason
this.status = REJECTED
this.onRejectedCallBacks.forEach(fn => fn()) // 发布
}
}
try {
executor(resolve,reject)
}catch(e){
reject(e)
}
}
then(onFulfilled, onRejected) {
// 如果then没有形参,则给实参赋默认值函数,接收参数返回参数即可实现值穿透,解决问题1
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
onRejected = typeof onRejected === 'function' ? onRejected : e => {throw e}
let promise2 = new Promise((resolve, reject) => {
if (this.status === RESOLVED) {
setTimeout(() => {
try {
// 重点
let x = onFulfilled(this.value)
resolvePromise(x, promise2, resolve, reject)
}catch(e) {
reject(e)
}
}, 0)
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
// 重点
let x = onRejected(this.value)
resolvePromise(x, promise2, resolve, reject)
}catch(e) {
reject(e)
}
}, 0)
}
if (this.status === PENDING) { // 订阅
this.onResolvedCallBacks.push(() => { // 函数中方便处理
setTimeout(() => {
try {
// 重点
let x = onFulfilled(this.value)
resolvePromise(x, promise2, resolve, reject)
}catch(e) {
reject(e)
}
}, 0)
})
this.onRejectedCallBacks.push(() => {
setTimeout(() => {
try {
// 重点
let x = onRejected(this.value)
resolvePromise(x, promise2, resolve, reject)
}catch(e) {
reject(e)
}
}, 0)
})
}
})
return promise2
}
}
module.exports = Promise
- 验证我们的promise是否符合PromiseA+规范
1) 首先,在promise实现的代码中,增加以下代码:
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
2) 安装测试脚本:
npm install -g promises-aplus-tests
如果当前的promise源码的文件名为promise.js
3) 那么在对应的目录执行以下命令: promises-aplus-tests promise.js
- 执行 promises-aplus-tests promise.js 结果
...
The value is `1` with `Number.prototype` modified to have a `then` method
✓ already-fulfilled
✓ immediately-fulfilled
✓ eventually-fulfilled
✓ already-rejected
✓ immediately-rejected
✓ eventually-rejected
872 passing (16s)
到此为此,我们的promise完成了,且符合PromiseA+规范。
做几道练习题巩固巩固
console.log(1);
async function async () {
console.log(2);
await console.log(3); // Promise.resolve(console.log(3)).then(()=>{4})
console.log(4)
}
setTimeout(() => {
console.log(5);
}, 0);
const promise = new Promise((resolve, reject) => {
console.log(6);
resolve(7)
})
promise.then(res => {
console.log(res)
})
async();
console.log(8);
Promise.resolve().then(()=>{ // then1
console.log(1);
Promise.resolve().then(()=>{ // then11
console.log(11);
}).then(()=>{
console.log(22); // then22
}).then(()=>{
console.log(33); // then33
})
}).then(()=>{ // then2
console.log(2);
}).then(()=>{ // then3
console.log(3);
})
async function async1(){ // node 11 结果不太一样
console.log('async1 start');
// node的其他版本可能会把await 解析出两个then 来
await async2(); // Promise.resolve(async2()).then(()=>{console.log('ok')})
}
async function async2(){
console.log('async2');
}
console.log('script start');
setTimeout(() => {
console.log('setTimeout')
}, 0);
async1();
new Promise(function(resolve){
console.log('promise1');
resolve()
}).then(function(){
console.log('script end')
})
promise的方法实现,包含Promise.resolve, Promise.reject, all, race, 取消promise,finally, catch, defer(延迟对象)
- Promise.resolve实现
Promise.resolve = function(val) {
return new Promise((resolve, reject) => {
resolve(val)
})
}
- Promise.reject实现
Promise.reject = function(val) {
return new Promise((resolve, reject) => {
reject(val)
})
}
- Promise.all实现
Promise.all = function(arr) {
return new Promise((resolve, reject) => {
let index = 0
let values = []
for (let i = 0; i<arr.length; i++) {
Promise.resolve(arr[i]).then(r => {
values[i] = r
if(++index === arr.length){
resolve(values)
}
}, y=>{
reject(y)
})
}
})
}
// 用例
Promise.all([1,2,3]).then(v=>{
console.log(v)
})
- Promise.race实现
Promise.race = function(arr) {
return new Promise((resolve, reject) => {
for(let i=0;i<arr.length;i++){
Promise.resolve(arr[i]).then(r=>{
resolve(r)
}, y=>{
reject(y)
})
}
})
}
// 用例
Promise.race([1,2,3]).then(r=>{
console.log(r)
})
- 取消promise
function wrap(promise) {
let abort = null
let abortPromise = new Promise((resolve, reject) => {
abort = reject
})
promise = Promise.race([promise, abortPromise])
promise.abort = abort
return promise
}
// 用例
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 2000);
})
let newPromise = wrap(promise)
setTimeout(() => {
newPromise.abort(12)
}, 1000);
newPromise.then(r => {
console.log(r)
}, y => {
console.log(y)
})
- finally实现
如果最后是错的,那就取最后错的值,如果一开始是错的,取一开始错的值。如果都是对的,取第一次对的值
// resolve(x) && resolve(y) => then resolve(x)
// resolve(x) && reject(y) => then reject(y)
// reject(x) && resolve(y) => then reject(x)
// reject(x) && reject(y) => then reject(y)
Promise.prototype.finally = function(cb) {
return this.then(value=> {
return Promise.resolve(cb()).then(()=>value, y=>y)
}, reason=>{
return Promise.resolve(cb()).then(()=>{throw reason})
})
}
// 用例
new Promise((resolve, reject) => {
reject(1)
}).finally(() => {
return new Promise((resolve, reject) => {
resolve(2)
})
}).then(r => {
console.log('r: ', r)
}, y => {
console.log('y: ', y)
})
- catch实现
Promise.prototype.catch = function(cb) {
return this.then(null, cb)
}
// 用例
new Promise((resolve, reject) => {
reject(1)
}).catch(() => {
console.log('catch')
})
// 等价于 ->
new Promise((resolve, reject) => {
reject(1)
}).then(null, () => {
console.log('catch')
})
- 延迟对象
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}