1、手写Promise
1.1 Promise构造函数
function Promise(executor) {
if (typeof excutor !== 'function') {
throw new TypeError(`promise value ${executor} is not function`)
}
this.state = 'pending'
this.resolverList = []
this.rejecterList = []
this.finallyList = []
this.data = null
const self = this
function resolve(data) {
if (data instanceof Promise) {
return data.then(self.resolve, self.reject)
}
setTimeout(function() {
if (self.state === 'pending') {
self.state = 'fulfilled'
self.data = data
while(self.resolverList.length) {
const resolver = self.resolverList.shift()
resolver(data)
}
while(self.finallyList.length) {
const finallyFn = self.finallyList.shift()
finallyFn(data)
}
}
})
}
function reject(reason) {
setTimeout(function(){
if (self.state === 'pending') {
self.state = 'rejected'
self.data = reason
while(self.rejecterList.length) {
const rejecter = self.rejecterList.shift()
rejecter(reason)
}
while(self.finallyList.length) {
const finallyFn = self.finallyList.shift()
finallyFn(data)
}
}
})
}
try {
excutor(resolve, reject)
} catch(err) {
reject(err)
}
}
1.2 关键的then函数
- 返回promise1对象
- 如果then钩子执行结果返回的是promise2,则promise2的钩子触发时会执行promise1的钩子
- 如果执行结果不是promies实例,则结果作为promise1的返回值
Promise.prototype.then = function(onResolve, onReject) {
onResolve = typeof onResolve === 'function' ? onResolve : function(data) { return data }
onReject = typeof onReject === 'function' ? onReject : function(reason) { return reason }
const self = this
if (self.state === 'fulfilled') {
return new Promise((resolve, reject) => {
try {
const result = onResolve(self.data)
if (result instanceof Promise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch(err) {
reject(err)
}
})
}
if (self.state === 'rejected') {
return new Promise((resolve, reject) => {
try {
const result = onReject(self.data)
if (result instanceof Promise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch(err) {
reject(err)
}
})
}
if (self.state === 'pending') {
return new Promise((resolve, reject) => {
self.resolverList.push(function() {
try {
const result = onResolve(self.data)
if (result instanceof Promise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch(err) {
reject(err)
}
})
self.rejecterList.push(function() {
try {
const result = onReject(self.data)
if (result instanceof Promise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch(err) {
reject(err)
}
})
})
}
}
1.3 catch函数
- 返回promise对象
- 函数的返回值作为promise的结果
Promise.prototype.catch = function(reject) {
return this.then(null, reject)
}
1.4 finally函数
Promise.prototype.finally = function(callback) {
this.finallyList.push(onFinally)
}
1.5 resolve函数
- 如果参数是promsie实例,则直接返回该实例
Promise.resolve = function(data) {
if (data instanceof Promise) {
return data
}
return new Promise((resolve, reject) => {
resolve(data)
})
}
1.6 reject函数
Promise.reject = function(reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
1.7 all函数
- 返回promise对象
- 所有状态都为fulfilled时才返回fulfilled,且结果按顺序排列
- 有一个rejected,则返回rejected
Promise.all = function(promiseList) {
if (!Array.isArray(promiseList)) {
throw new TypeError(`${promiseList} is not iterable`)
}
return new Promise((resolve,reject) => {
let idx = 0
let resolverList = Array(promiseList.length)
for (let index = 0; index < promiseList.length; index++) {
const p = promiseList[index];
p.then(res => {
idx += 1
resolverList[index] = res
}, reject).finally(() => {
if (idx === promiseList.length) {
resolve(resolverList)
}
})
}
})
}
1.8 any函数
- 返回promise对象
- 所有状态都为rejected时才返回rejected,且结果按顺序排列
- 有一个fulfilled,则返回fulfilled
Promise.any = function(promiseList) {
if (!Array.isArray(promiseList)) {
throw new TypeError(`${promiseList} is not iterable`)
}
return new Promise((resolve,reject) => {
let idx = 0
let rejecterList = Array(promiseList.length)
for (let index = 0; index < promiseList.length; index++) {
const p = promiseList[index];
p.then(resolve, rej => {
idx += 1
rejecterList[index] = rej
}).finally(() => {
if (idx === promiseList.length) {
reject(rejecterList)
}
})
}
})
}
1.9 race函数
- 返回promise对象
- 谁先出结果,就返回谁的结果
Promise.race = function(promiseList) {
if (!Array.isArray(promiseList)) {
throw new TypeError(`${promiseList} is not iterable`)
}
return new Promise((resolve, reject) => {
while (promiseList.length) {
const p = promiseList.shift()
p.then(resolve, reject)
}
})
}
1.10 allSettled函数
- 返回promsie对象
- 返回状态永远是fulfilled
- 按顺序返回所有的结果
Promise.allSettled = function(promiseList) {
if (!Array.isArray(promiseList)) {
throw new TypeError(`${promiseList} is not iterable`)
}
let idx = 0
let result = Array(promiseList.length)
return new Promise((resolve) => {
for (let index = 0; index < promiseList.length; index++) {
const p = promiseList[index];
p.then(res => {
result[index] = { status: 'fulfilled', value: res}
}, rej => {
result[index] = { status: 'rejected', value: rej}
}).finally(() => {
idx+=1
if (idx === promiseList.length) {
resolve(result)
}
})
}
})
}
1.11 加强版then函数
Promise.prototype.then = function(onResolve, onReject){
onResolve = typeof onResolve === 'function' ? onResolve : function(data) { return data }
onReject = typeof onReject === 'function' ? onReject : function(reason) { return reason }
const self = this
let promise2 = null
if (self.state === 'fulfilled') {
return promise2 = new Promise((resolve, reject) => {
try {
const result = onResolve(self.data)
resolvePromise(promise2, result, resolve, reject)
} catch(err) {
reject(err)
}
})
}
if (self.state === 'rejected') {
return promise2 = new Promise((resolve, reject) => {
try {
const result = onReject(self.data)
resolvePromise(promise2, result, resolve, reject)
} catch(err) {
reject(err)
}
})
}
if (self.state === 'pending') {
return promise2 = new Promise((resolve, reject) => {
self.resolverList.push(function() {
try {
const result = onResolve(self.data)
resolvePromise(promise2, result, resolve, reject)
} catch(err) {
reject(err)
}
})
self.rejecterList.push(function() {
try {
const result = onReject(self.data)
resolvePromise(promise2, result, resolve, reject)
} catch(err) {
reject(err)
}
})
})
}
}
function resolvePromise(promise, result, resolve, reject) {
if (promise === result) {
throw new TypeError('Chaining cycle detected for promise!')
}
if (result instanceof Promise) {
if (result.state === 'pending') {
result.then(function(res){
resolvePromise(promise, res, resolve, reject)
}, reject)
} else {
result.then(resolve, reject)
}
return
}
let called = false
if (result !== null && (typeof result === 'object' || typeof x ==== 'function')) {
try {
let then = result.then
if(typeof then === 'function') {
then.call(result, function(res) {
if (called) return
called = true
resolvePromise(promise, res, resolve, reject)
}, function(rej) {
if (called) return
called = true
reject(rej)
})
} else {
resolve(result)
}
} catch(err) {
if (called) return
called = true
reject(err)
}
}
}
2、手写new、bind、call、apply
2.1 new
- 创建一个新对象
- 新对象的原型链继承构造函数的原型(继承构造函数原型)
- 通过call函数执行构造函数中的代码(为新对象添加构造函数的属性,继承自有属性)
- 构造函数执行结果是引用类型或者函数则直接该结果,否则返回新对象
function _new(ctor, ...args) {
if (typeof ctor !== 'function') {
throw new TypeError(`${ctor} is not a constructor`)
}
const o = {}
o.__proto__ = Object.create(ctro.prototype)
const res = ctor.call(o, ...args)
let isObject = typeof res === 'object' && res !== null;
let isFunction = typeof res === 'function';
return isObject || isFunction ? res : obj;
}
2.2 call函数
Function.prototype.call = function(context, args) {
const fn = this;
context = context ?? window;
context.fn = fn;
const res = context.fn(...args)
delete context.fn
return res
}
2.3 apply函数
Function.prototype.apply = function(context, args) {
const fn = this
context = context ?? window
context.fn = fn
const res = context.fn(args)
delete context.fn
return res
}
2.4 bind函数
- 返回一个新函数
- 新函数继承原函数的原型
- 当新函数被当作构造函数执行时,不绑定新this
function isCallable(target) {
if (typeof target !== 'function') {
return false
}
if (typeof target.call !== 'function') {
return false
}
return true
}
const factories = {}
function construct(C, argsLength, args) {
if (!factories.hasOwnProperty(argsLength)) {
let list = []
for (let i = 0; i < argsLength; i++) {
list[i] = `a[${i}]`;
}
factories[argsLength] = Function('C,a', `return new C(${list})`);
}
return factories[argsLength](C, args)
}
Function.prototype.bind = function(that, ...partArgs){
let F = this
if (!isCallable(F)) {
throw new TypeError(`${F} is not function or not has call method`)
}
const Prototype = F.prototype
const boundFunction = function bound() {
const args = Array.prototype.push.call(partArgs, arguments)
return this instanceof boundFunction ? construct(F, args.length, args) : F.apply(that, args)
}
if (typeof Prototype === 'object') {
boundFunction.prototype = Prototype
}
return boundFunction
}
3、手写数组API
3.1 push方法
Array.prototype.push = function(...args) {
const o = Object(this)
const len = this.length >>> 0
const argLen = args.length >>> 0
if (len + argLen > 2 ** 53 - 1) {
throw new TypeError("The number of array is over the max value")
}
for(let i = 0; i < argLen; i++) {
o[len + 1] = args[i]
}
const newLen = len + argLen
o.length = newLen
return newLen
}
3.2 pop方法
Array.prototype.pop = function() {
const o = Object(this)
const len = this.length >>> 0
if (len === 0) {
return undefined
} else {
const newLen = len - 1
const element = o[newLen]
delete o[newLen]
o.length = newLen
return element
}
}
3.3 map方法
Array.prototype.map = function(callback, thisObject) {
const o = Object(this)
const len = this.length >>> 0
if (typeof callback !== 'function') {
throw new TypeError(callback + 'is not a function')
}
const A = Array(len)
let k = 0
while (k < len) {
if (k in o) {
const val = callback.call(thisObject, o[k], k, o)
A[k] = val
}
k ++
}
return A
}
3.4 reduce方法
Array.prototype.reduce = function(callback, initialValue){
const o = Object(this)
const len = this.length >>> 0
if (typeof callback !== 'function') {
throw new TypeError(callback + 'is not a function')
}
if (len === 0 && !initialValue) {
throw new TypeError('Reduce of empty array with no initial value')
}
let k = 0;
var accumulator;
if (initialValue) {
accumulator = initialValue
} else {
let kPresent = false;
while (!kPresent && k < len) {
if (k in o) {
accumulator = o[k]
kPresent = true
}
k ++
}
if (!kPresent) {
throw new TypeError('Reduce of empty array with no initial value')
}
}
while(k < len) {
if (k in o) {
accumulator = callback(accumulator, o[k], k, o)
}
k++
}
return accumulator
}
4、手写EventEmitter
4.1 EventEmitter构造函数
function EventEmitter() {
this._event = {}
}
function isValidListener(listener) {
if (typeof listener === 'function') {
return true
} else if (typeof listener === 'object') {
return isValidListener(listener.listener)
}
return false
}
function indexOf(array, item) {
let result = -1
item = typeof item === 'object' ? item.listener : item
for (let i = 0; i < array.length; i++) {
if (array[i].listener === item) {
result = i
break
}
return result
}
4.2 on方法
EventEmitter.prototype.on = function(eventName, listener) {
if (eventName && listener) {
const listenerList = this._event[eventName] ?? []
if (!isValidListener(listener)) {
throw new TypeError(`${listener} is not a function`)
}
if (indexOf(listenerList, listener) === -1) {
const listenerIsWrapped = typeof listener === 'object'
listenerList.push(listenerIsWrapped ? listener : {
listener,
once: false
})
}
this._event[eventName] = listenerList
}
}
4.3 emit方法
EventEmitter.prototype.emit = function(eventName, ...args) {
if (eventName) {
const listenerList = this._event[eventName]
if (listenerList?.length) {
for (let i = 0; i < listenerList.length; i++) {
const listener = listenerList[i]
if (listener) {
listener.listener.call(this, ...args)
if (listener.once) {
this.off(eventName, listener.listener)
}
}
}
}
}
}
4.4 off方法
EventEmitter.prototype.off = function(eventName, listener) {
if (eventName && listener) {
const listenerList = this._event[eventName]
if (listenerList?.length) {
const idx = indexOf(listenerList, listener)
if (idx !== -1) {
listenerList.splice(idx, 1)
}
}
}
}
4.5 once方法
EventEmitter.prototype.once = function(eventName, listener) {
this.on(eventName, {listener, once: true})
}
4.6 offAll方法
EventEmitter.prototype.offAll = function(eventName) {
if (eventName) {
this._event[eventName] = []
} else {
this._event = {}
}
}