const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";
function resolvePromise(x, promise2, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('循环引用'))
}
if (typeof x === 'object' && x !== null || typeof x === 'function') {
let called;
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, (value) => {
if (called) return;
called = true;
resolvePromise(value, promise2, resolve, reject)
}, (error) => {
if (called) return;
called = true;
reject(error)
})
} else {
resolve(x)
}
} catch (e) {
if (called) return;
called = true;
reject(e)
}
} else {
resolve(x)
}
}
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolveCallbacks = []
this.onRejectCallbacks = []
const resolve = (value) => {
if (value instanceof Promise) {
return value.then(resolve, reject)
}
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
this.onResolveCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
this.onRejectCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (data) {
return data
}
onRejected = typeof onRejected === 'function' ? onRejected : err => {
throw err
}
let promise2 = new Promise((resolve, reject) => {
if (this.status === PENDING) {
this.onResolveCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
this.onRejectCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
}
if (this.status === FULFILLED) {
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.reason)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e)
}
})
}
})
return promise2
}
catch (errCallback) {
return this.then(null, errCallback)
}
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 times = 0;
const arr = []
function processMap(key, value) {
arr[key] = value;
if (++times === promises.length) {
resolve(arr)
}
}
for (let i = 0; i < promises.length; i++) {
let promise = promises[i];
let then = promise && promise.then
if (typeof then === 'function') {
then.call(promise, (data) => {
processMap(i, data)
}, reject)
} else {
processMap(i, promise)
}
}
})
}
finally(cb) {
return this.then((y) => {
return Promise.resolve(cb()).then(() => y, (err) => {
throw err
})
}, (err) => {
return Promise.resolve(cb()).then(() => {
throw err
})
})
}
static race(values) {
return new Promise((resolve, reject) => {
for (let i = 0; i < values.length; i++) {
let p = values[i]
Promise.resolve(p).then(resolve, reject)
}
})
}
}
Promise.deferred = function () {
let dfd = {}
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject
})
return dfd
}
function readFile(...args) {
let dfd = Promise.deferred();
fs.readFile(...args, function (err, data) {
if (err) return dfd.reject(err)
dfd.resolve(data)
})
return dfd.promise
}
module.exports = Promise
``
|