一、js篇
1、防抖函数
防抖:指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间
function debounce(fn,t){
let timer=0
// 返回一个匿名函数,为了能够一直调用
return function(){
// 如果已经存在setTimeout定时器先删除,再添加新定时器
if(timer) clearTimeout(timer)
timer=setTimeout(function(){
fn()
},t)
}
}
2、节流函数
节流:连续触发事件但是在 n 秒中只执行一次函数
function throttle(fn,t){
let timer
return function(){
// 和防抖区别在于清空定时器放在setTimeout里面
if(!timer){
timer=setTimeout(function(){
fn()
// 不能用clearTimeout,因为在定时器运行中情况定时器是不合理的
timer=null
},t)
}
}
}
3、call函数
4、apply函数
5、bind函数
6、Promise
Promise的自定义封装和一些API的封装
// 我自己的Promise构造函数
// 这里的executor是接住了一个匿名函数,所以可以加括号传参调用
function Promise(executor) {
// 添加属性
this.promiseState = 'pending'
this.promiseResult = null
// 声明属性
this.callbacks = []
// 保存实例对象this的值,因为resolve调用是直接 resolve('OK')这样调用,所以他的this是指向window的
const self = this
// resolve函数
function resolve(data) {
// 判断状态,保证状态只被修改一次
if (self.promiseState !== 'pending') return
// 1、改变状态(promiseState)
self.promiseState = 'fulfilled'//resolved
// 2、设置对象结果值(promiseResult)
self.promiseResult = data
// 调用成功的回调函数
// 当我的函数是异步时,也就是executor中有个定时器,就会在定时器结束后才会改变状态
// 就会导致不会触发then,因为then中是有状态===fulfilled或rejected才会调用我传入的匿名函数
// 所以加上pending状态的判断,当我状态没改变就运行到then时(有个定时器),
// 用一个对象保存下两个匿名函数,当定时器时间结束,执行executor时
// 就会调用对应的resolve或reject,就会调用到这里
// 从而去调用then中的匿名函数,实现状态改变之后再回调
setTimeout(() => {
self.callbacks.forEach(item => {
item.onResolved(data)
})
})
}
// reject函数
function reject(data) {
// 判断状态,保证状态只被修改一次
if (self.promiseState !== 'pending') return
// 1、改变状态(promiseState)
self.promiseState = 'rejected'
// 2、设置对象结果值(promiseResult)
self.promiseResult = data
// 调用失败的回调函数
setTimeout(() => {
self.callbacks.forEach(item => {
item.onRejected(data)
})
})
}
try {
// 同步调用executor函数
executor(resolve, reject)
} catch (error) {
// 修改promise对象状态为失败
reject(error);
}
}
// 原型中定义then
// 这里的onResolved和onRejected是接住了一个匿名函数,所以可以加括号传参调用
Promise.prototype.then = function (onResolved, onRejected) {
const self = this// 这个self是p
// 这里是实现catch的异常穿透
// 因为原版的promise在使用异常穿透的时候,允许用户在then只传入一个参数
// 也就是成功时候的回调函数,失败的回调函数统一到catch中处理
// 判断回调函数参数,也就是我没传入onRejected参数
// 没传onRejected参数时,为防止报undifild错误,直接默认指定一个
if (typeof onRejected != 'function') {
onRejected = reason => {
throw reason
}
}
// 实现值传递功能,也就是第一个参数onResolved不传入
if (typeof onResolved != 'function') {
onResolved = value => {
return value
}
}
// 使用之前的this.callbacks.push({
// onResolved: onResolved,
// onRejected: onRejected
// 这样只能完成p的异步操作,因为这个新生成的Promise并没有进行改变状态
// 因为在resolve函数中调用数组进行改变的self是指向p的
return new Promise((resolve, reject) => {
// 将重复部分进行封装
function callback(type) {
try {
// 封装之后这里是self了,因为封装到函数里this指针指向的就是window了
let result = type(self.promiseResult)
if (result instanceof Promise) {
result.then(v => {
resolve(v)
}, r => {
reject(r)
})
} else {
// 变为成功,因为return 111,或者其他都是成功
resolve(result);
}
} catch (e) {
reject(e)
}
}
// 调用回调函数
// 这里的this指向调用者,也就是p
// console.log(this==p);//ture
if (this.promiseState === 'fulfilled') {
// // 这里是同步状态下(没有定时器)改变返回的promise的状态
// try {
// // 获取回调函数返回结果,是then中的匿名函数的执行结果,
// // console.log(111) 就是undefined,return 111 时 就是111
// let result = onResolved(this.promiseResult)
// // 判断,也就是then中的语句是返回一个promise对象,还是返回普通类型的值(比如return 111,或console.log())
// if (result instanceof Promise) {
// result.then(v => {
// resolve(v)
// }, r => {
// reject(r)
// })
// } else {
// // 变为成功,因为return 111,或者其他都是成功
// resolve(result);
// }
// } catch (e) {
// reject(e)
// }
// 实现原版promise中的then中的回调函数是异步的
setTimeout(() => {
callback(onResolved)
})
}
if (this.promiseState === 'rejected') {
// try {
// let result = onRejected(this.promiseResult)
// if (result instanceof Promise) {
// result.then(v => {
// resolve(v)
// }, r => {
// reject(r)
// })
// } else {
// resolve(result);
// }
// } catch (e) {
// reject(e)
// }
setTimeout(() => {
callback(onRejected)
})
}
// 判断pending状态,实现异步操作,比如加一个定时器
if (this.promiseState === 'pending') {
// 为了等异步操作结束,改变状态之后执行
// 保存回调函数
// console.log(self==p);//ture
this.callbacks.push({
onResolved: function () {
// // 这是异步状态下改变返回的promise的状态,
// // 因为异步状态下p的状态是pending,会走这个函数
// // 走不了上面定义好的那个resolved用来改变状态
// // 只能走到这里,改变状态,异步就是要用一个对象保存下来回调函数
// // 执行成功的回调函数,result是函数中return的东西
// try {
// let result = onResolved(self.promiseResult)
// // console.log(self == p);//ture
// // 判断
// if (result instanceof Promise) {
// // return promise会有两种状态选择
// result.then(v => {
// resolve(v)
// }, r => {
// reject(r)
// })
// } else {
// // 只有一种状态选择
// resolve(result)
// }
// } catch (error) {
// reject(error)
// }
callback(onResolved)
},
onRejected: function () {
// try {
// let result = onRejected(self.promiseResult)
// // console.log(self==p);//ture
// // 判断
// if (result instanceof Promise) {
// // return promise会有两种状态选择
// result.then(v => {
// resolve(v)
// }, r => {
// reject(r)
// })
// } else {
// // 只有一种状态选择
// resolve(result)
// }
// } catch (error) {
// reject(error)
// }
callback(onRejected)
}
})
}
})
}
// 添加catch方法
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
// 添加resolve方法,注意这个方法是构造函数的方法,而不是实例的方法
// 跟Promise中的实现then返回对象是promise,并且状态改变的那部分代码一样
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(v => {
resolve(v)
}, r => {
reject(r)
})
} else {
resolve(value)
}
})
}
// reject方法
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
// all方法,参数是Promise的数组
Promise.all = function (promises) {
// 返回结果是promise对象
return new Promise((resolve, reject) => {
let count = 0
// 保存结果的数组
let arr = []
// 遍历promise数组(参数),判断每个promise对象状态
for (let i = 0; i < promises.length; i++) {
// 其实一个promise对象在then中去调用resolve或reject函数
// 修改的是这个对象的then方法返回的新promise对象的状态
// 这里的promise[i]如果是成功的状态会走上面的函数,失败走下面的函数,这是promise对象的then方法的特性
promises[i].then(v => {
// 得知对象的状态是成功
// 每个promise对象都成功
count++
// 还需要将每个promise对象的状态结果存入数组当中
// 这样保证顺序不会乱
arr[i] = v
// 都成功
if (count === promises.length) {
resolve(arr)
}
}, r => {
// 有一个promise失败,则这个new Promise就是失败的
reject(r)
})
}
})
}
// race方法,谁先改变状态,返回的promise就是谁的状态
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(v => {
resolve(v)
}, r => {
reject(r)
})
}
})
}