Last active
July 29, 2022 14:11
-
-
Save SoarLin/2fd4bbfd7f6142d1ac338d0c756ab4dd to your computer and use it in GitHub Desktop.
Implement Promise
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
}) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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