Skip to content

Commit

Permalink
promise 实现2
Browse files Browse the repository at this point in the history
  • Loading branch information
abstain23 committed Jun 6, 2020
1 parent ef5fa72 commit 209d154
Show file tree
Hide file tree
Showing 11 changed files with 454 additions and 0 deletions.
1 change: 1 addition & 0 deletions 0606/age.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22
33 changes: 33 additions & 0 deletions 0606/event.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const fs = require('fs')
let cc = {}

let event = {
arr:[],
on(fn) {
this.arr.push(fn)
},
emit() {
this.arr.forEach(fn => fn())
}
}

event.on(() => {
console.log('订阅ok')
})

event.on(() => {
// console.log(Object.keys(cc))
// console.log(Object.keys(cc))
if(Object.keys(cc).length === 2) {
console.log(cc)
}
})

fs.readFile('name.txt', (err, data) => {
cc['name'] = data.toString()
event.emit()
})
fs.readFile('age.txt', (err, data) => {
cc['age'] = data.toString()
event.emit()
})
16 changes: 16 additions & 0 deletions 0606/fs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const fs = require('fs')
let cc = {}

const after = (times, fn) => () => --times === 0 && fn()
let newA = after(2, ()=> {
console.log(cc)
})

fs.readFile('name.txt', (err, data) => {
cc['name'] = data.toString()
newA()
})
fs.readFile('age.txt', (err, data) => {
cc['age'] = data.toString()
newA()
})
1 change: 1 addition & 0 deletions 0606/name.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cc
120 changes: 120 additions & 0 deletions 0606/pormise2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
class MyPromise {
constructor(executor) {
// 初始属性值
this.status = 'pending';
this.value = undefined;
this.resolvedArr = [];
this.rejectedArr = [];

// 改变状态的函数
let changeStatus = (status, result) => {
if (this.status !== 'pending') return;
this.status = status;
this.value = result;
let arr = status === 'rejected' ? this.rejectedArr : this.resolvedArr;
arr.forEach(item => (typeof item === 'function' ? item(this.value) : null));
};
let resolve = result => {
if (this.resolvedArr.length > 0) {
changeStatus('resolved', result);
return;
}
let delayTimer = setTimeout(() => {
clearTimeout(delayTimer);
changeStatus('resolved', result);
}, 0);
};
let reject = reason => {
if (this.rejectedArr.length > 0) {
changeStatus('rejected', reason);
return;
}
let delayTimer = setTimeout(() => {
clearTimeout(delayTimer);
changeStatus('rejected', reason);
}, 0);
};

// 异常捕获处理
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}

then(resolvedFn, rejectedFn) {
if (typeof resolvedFn !== 'function') {
resolvedFn = result => {
return result;
};
}
if (typeof rejectedFn !== 'function') {
rejectedFn = reason => {
// throw new Error(reason);
return new MyPromise((resolve, reject) => {
reject(reason);
});
};
}

// then链:返回一个新的Promise实例
return new MyPromise((resolve, reject) => {
this.resolvedArr.push(() => {
try {
let x = resolvedFn(this.value);
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
} catch (error) {
reject(error);
}
});
this.rejectedArr.push(() => {
try {
let x = rejectedFn(this.value);
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
} catch (error) {
reject(error);
}
});
});
}

catch (rejectedFn) {
// catch(rejectedFn) === then(null,rejectedFn)
return this.then(null, rejectedFn);
}

/* 静态方法 */
static resolve(result) {
return new MyPromise(resolve => {
resolve(result);
});
}

static reject(reason) {
return new MyPromise((_, reject) => {
reject(reason);
});
}

static all(arr) {
return new MyPromise((resolve, reject) => {
let index = 0,
results = [];
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
if (!(item instanceof MyPromise)) continue;
item.then(result => {
index++;
results[i] = result;
if (index === arr.length) {
resolve(results);
}
}).catch(reason => {
// 只要有一个失败,整体就是失败
reject(reason);
});
}
});
}
}
201 changes: 201 additions & 0 deletions 0606/promise.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
const resolvePromise = (promise2, x, resolve, reject) => {
if (promise2 === x) {
// console.log('==')
return reject(new TypeError('不能返回自己'))
}

if(x && typeof x === 'object' || typeof x === 'function') {
let called // 默认没有调用成功
try {
let then = x.then // 取then的时候可能会发生错误 例如getter
if(typeof then === 'function') {
then.call(x, y => {
// resolve(y)
// 递归解析promise
if(called) return // 防止多次调用
called = true
resolvePromise(promise2, y, resolve, reject)
},r => {
if(called) return
called = true
reject(r)
})
}
} catch (error) {
if(called) return
called = true
reject(error)
}
} else {
resolve(x)
}
}
class Promise {
constructor(excutor) { // excutor 立即执行的
this.state = PENDING
this.value = undefined
this.reason = undefined
this.onResolvedCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => { //成功
if(value instanceof Promise) {
return value.then(resolve, reject)
}
if (this.state === PENDING) {
this.state = RESOLVED
this.value = value
this.onResolvedCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
this.state = REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn())
}
try {
excutor(resolve, reject) // 出错直接到reject
} catch (error) {
reject(error)
}
}

then(onResolved, onRejected) {
// 可选参数 穿透
onResolved = typeof onResolved === 'function' ? onResolved : value => value
onRejected = typeof onRejected === 'function' ? onRejected : err => {throw err}
// then 方法应该返回一个新的promise
let promise2 = new Promise((resolve, reject) => {
if (this.state === RESOLVED) {
// console.log('resolved')
setTimeout(() => {
try {
let res = onResolved(this.value)
// console.log(res)
resolvePromise(promise2, res, resolve, reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === REJECTED) {
// console.log('rejected')
setTimeout(() => {
try {
let res = onRejected(this.reason)
resolvePromise(promise2, res, resolve, reject)
} catch (error) {
reject(error)
}
})
}
if (this.state === PENDING) {
// console.log('pending')
this.onResolvedCallbacks.push(() => {
// onResolved(this.value)
setTimeout(() => {
try {
let res = onResolved(this.value)
// console.log(res)
resolvePromise(promise2, res, resolve, reject)
} catch (error) {
reject(error)
}
})
})
this.onRejectedCallbacks.push(() => {
// onRejected(this.reason)
setTimeout(() => {
try {
let res = onRejected(this.reason)
resolvePromise(promise2, res, resolve, reject)
} catch (error) {
reject(error)
}
})
})
}
})
return promise2
}
catch(onRejected) {
return this.then(null, onRejected)
}
static resolve(value) {
return new Promise(resolve => {
resolve(value)
})
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
static all(promises) {
return new Promise((resolve, reject) => {
let index = 0, results = []
for(let i = 0; i< promises.length; i++) {
let item = promises[i]
if(item instanceof Promise) {
item.then(res => {
results[i] = res
index ++
if(index === promises.length) {
resolve(results)
}
}).catch(reason => {
reject(reason)
})
} else {
results[i] = item
index ++
if(index === promises.length) {
resolve(results)
}
}
}
})
}
static race(promises) {
return new Promise((resolve, reject) => {
promises.forEach(item => {
if(item instanceof Promise) {
item.then(res => resolve(res))
} else {
resolve(item)
}
})
})
}
}

module.exports = Promise

/*
const handle = (cb, data) => {
try {
const res = cb(data)
res instanceof Promise ? res.then(resolve, reject) : resolve(res)
} catch (error) {
reject(error)
}
}
if(this.state === RESOLVED) {
handle(onResolved, this.value)
}
if(this.state === REJECTED) {
handle(onRejected, this.reason)
}
if(this.state === PENDING){
this.onResolvedCallbacks.push(() => {
// onResolved(this.value)
handle(onResolved, this.value)
})
this.onRejectedCallbacks.push(() => {
// onRejected(this.reason)
handle(onRejected, this.reason)
})
}
*/
Loading

0 comments on commit 209d154

Please sign in to comment.