Skip to content

Instantly share code, notes, and snippets.

@SoarLin
Last active July 29, 2022 14:11
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 SoarLin/2fd4bbfd7f6142d1ac338d0c756ab4dd to your computer and use it in GitHub Desktop.
Save SoarLin/2fd4bbfd7f6142d1ac338d0c756ab4dd to your computer and use it in GitHub Desktop.
Implement Promise
MyPromise.prototype.catch = function(catchFunc) {
return this.then(null, catchFunc)
}
MyPromise.resolve = function(value) {
return new MyPromise((resolve, reject) => {
resolve(value);
})
}
MyPromise.reject = function(value) {
return new MyPromise((resolve, reject) => {
reject(value);
})
}
MyPromise.all = function(promiseArray) {
if (!Array.isArray(promiseArray)) {
throw new TypeError('The arguments should be an array!');
}
return new MyPromise((resolve, reject) => {
try {
let resultArray = [];
const length = promiseArray.length;
for (let i = 0; i < length; i++) {
promiseArray[i].then(data => {
resultArray.push(data)
if (resultArray.length === length) {
resolve(resultArray)
}
}, reject)
}
} catch (err) {
reject(err)
}
})
}
MyPromise.race = function(promiseArray) {
if (!Array.isArray(promiseArray)) {
throw new TypeError('The arguments should be an array!');
}
return new MyPromise((resolve, reject) => {
try {
const length = promiseArray.length;
for (let i = 0; i < length; i++) {
promiseArray[i].then(resolve, reject);
}
} catch (e) {
reject(e)
}
})
}
function MyPromise(executor) {
this.status = 'pending'
this.value = null
this.reason = null
this.onFulfilledArray = []
this.onRejectedArray = []
const resolve = (value) => {
if (value instanceof MyPromise){
return value.then(resolve, reject)
}
setTimeout(() => {
if (this.status === 'pending') {
this.value = value
this.status = 'fulfilled'
this.onFulfilledArray.forEach(func => {
func(value)
})
}
})
}
const reject = (reason) => {
setTimeout(() => {
if (this.status === 'pending') {
this.reason = reason
this.status = 'rejected'
this.onRejectedArray.forEach(func => {
func(reason)
})
}
})
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
const resolvePromise = (promise2, result, resolve, reject) => {
if (result === promise2) {
reject(new TypeError('error due to circular reference'))
}
let consumed = false
let thenable
if (result instanceof MyPromise) {
if (result.status === 'pending') {
result.then(function(data) {
resolvePromise(promise2, data, resolve, reject)
}, reject)
} else {
result.then(resolve, reject)
}
return
}
let isComplexResult = (target) => (typeof target === 'function' || typeof target === 'object') && (target !== null)
if (isComplexResult(result)) {
try {
thenable = result.then
if (typeof thenable === 'function') {
thenable.call(result, function(data) {
if (consumed) return
consumed = true
return resolvePromise(promise2, data, resolve, reject)
}, function(error) {
if (consumed) return
consumed = true
return reject(error)
})
} else {
resolve(result)
}
} catch (e) {
if (consumed) return;
consumed = true;
return reject(e)
}
} else {
resolve(result)
}
}
MyPromise.prototype.then = function(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : data => data
onRejected = typeof onRejected === 'function' ? onRejected : error => {throw error}
let promise2
if (this.status === 'fulfilled') {
return promise2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
try {
let result = onFulfilled(this.value)
resolvePromise(promise2, result, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
if (this.status === 'rejected') {
return promise2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
try {
let result = onRejected(this.value)
resolvePromise(promise2, result, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
if (this.status === 'pending') {
return promise2 = new MyPromise((resolve, reject) => {
this.onFulfilledArray.push(() => {
try {
let result = onFulfilled(this.value)
resolvePromise(promise2, result, resolve, reject)
} catch (e) {
reject(e)
}
})
this.onRejectedArray.push(() => {
try {
let result = onRejected(this.reason)
resolvePromise(promise2, result, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment