Skip to content

Instantly share code, notes, and snippets.

@zyf0330
Last active July 2, 2017 06:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zyf0330/01f2115ba32e031c018f77b898628e4c to your computer and use it in GitHub Desktop.
Save zyf0330/01f2115ba32e031c018f77b898628e4c to your computer and use it in GitHub Desktop.
My Promise implement. Must run in Node.js. 只是一个没有按照标准实现的残次品
let id = 1
function Promise(executor) {
this.id = id++
this.status = 'pending'
this.value = null
this._next = null
const response = (status, v) => {
if (this.status != 'pending') {
return
}
this.value = v
this.status = status
setTimeout(() => {
this._run()
})
}
const res = (v) => {
response('resolved', v)
}
const rej = (v) => {
response('rejected', v)
}
this._run = () => {
let _next = this._next
let expectNext = null
const expectType = this.status == 'resolved' ? 'then' : 'catch'
while (expectNext == null && _next != null) {
if (_next.type == expectType) {
expectNext = _next
} else {
_next = _next.p._next
}
}
if (expectNext != null) {
if (expectNext.called) return
expectNext.called = true
let result
try {
result = expectNext.func(this.value)
} catch (e) {
return expectNext.rej(e)
}
if (result instanceof Promise == false) {
result = expectNext.res(result)
} else {
result.then(expectNext.res).catch(expectNext.rej)
}
} else if (this.status == 'rejected') {
throw this.value
}
}
try {
executor(res, rej)
} catch (e) {
rej(e)
}
}
Promise.prototype.chain = function (type, func) {
const _next = this._next = {type: type, called: false}
const p = new Promise(function (res, rej) {
_next.res = res
_next.rej = rej
})
_next.func = func
_next.p = p
setImmediate(() => {
this._run()
})
if (type == 'catch') {
if (unhandledPromiseError != null) {
process.nextTick(() => {
console.error('async promise error handle', unhandledPromiseError);
unhandledPromiseError = null
})
}
}
return p
}
Promise.prototype.then = function (func) {
return this.chain('then', func)
}
Promise.prototype.catch = function (func) {
return this.chain('catch', func)
}
Promise.prototype.toString = function () {
return `Promise <${this.status} ${this.value}>`
}
Promise.resolve = (v) => {
const p = new Promise((res) => res(v))
return p
}
Promise.reject = (v) => {
const p = new Promise((res, rej) => rej(v))
return p
}
Promise.all = (promises) => {
let finish = 0
const results = []
return new Promise((res, rej) => {
promises.forEach((promise, i) =>
promise
.then((v) => {
results[i] = v;
finish += 1
if (finish == promises.length) {
res(results)
}
})
.catch((e) => {
rej(e)
})
)
})
}
Promise.race = (promises) => {
let finish = false
return new Promise((res, rej) => {
promises.forEach((promise, i) =>
promise
.then((v) => {
if (finish) {
return
}
finish = true
res(v)
})
.catch((e) => {
if (finish) {
return
}
finish = true
rej(e)
})
)
})
}
let unhandledPromiseError = null
// TODO 这里应该使用 domain 来捕获错误
process.on('uncaughtException', (err) => {
if (unhandledPromiseError != null) {
return
}
console.error('unhandled promise rejection:', err)
unhandledPromiseError = err
});
module.exports = Promise
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment