满足以下条件之一:
定义: 有权访问另一个函数作用域中变量的函数(来源红宝书
)
柯里化(Currying),把接受多个参数的函数转换成接受一个单一参数的函数
let add = function(x) { return function(y) { return x + y } } add(3)(4) // 7 复制代码
实际开发如果需要用到 柯里化,推荐使用 lodash.curry
typeof
无法判断 对象 类型
constructor
判断 是谁构造出来的
instanceof
判断 谁是谁的实例(即引用类型)
Object.prototype.toString.call()
完美判断
function isType(type) { return function (content) { return Object.prototype.toString.call(content) === `[object ${type}]` } } let isString = isType('String') console.log(isString('132456')) // 函数柯里化 console.log(isType('Number')(132456)) 复制代码
也成为 装饰者模式
定义:
指在不修改原有代码的情况下增加新功能
function sleep(who) { who?console.log(who + '睡觉'):console.log('睡觉') } Function.prototype.before = function (callback) { return (...args)=> {// args 传入的参数数组 callback() args?this(...args):this() // 传入参数 } } let Wash = sleep.before(function () { console.log('洗脸') }) Wash() // 洗脸 睡觉 Wash('我') // 洗脸 我睡觉 复制代码
有挣议
,有些人说这个不算是观察者模式。个人觉得算是属于
let e = { _obg:{}, // 事件 _callback:[], // 处理函数列表 on(callback) { // 订阅 this._callback.push(callback) }, emit(key,value){ // 发布 this._obg[key] = value this._callback.forEach(fn=>{ fn(this._obg) // 参数传入 }) } } e.on(function (obj) { console.log('发布一个') console.log(obj) }) setTimeout(function () { e.emit('name','琛') },1000) 复制代码
举一个简单的例子,即微博,你关注了A,A发动态就会通知你。你和A没有直接联系,通过 微博自己的调度来完成
发布订阅模式
是 两者之间没有直接关系,通过实践调度中心来完成。而观察者模式
是相互依赖的,一个改变。另一个也发生改变
// 设计模式 观察者模式 // 与发布订阅两者区别 // 发布订阅 是基于一个中间管理 on 和 emit 没有直接关系 // 观察者模式 是 Observer and Observed 有直接关系 // 一个依赖改变,另一个也改变 Vue class Observer { // 观察者 constructor(name) { // 传递参数 this.name = name } update(baby){ console.log(this.name+'知道'+baby.name+baby.state) } } class Observed{ // 被观察者 constructor(name) { this.name = name this.state = '开心' this.Observer = [] } addObserver(o){ this.Observer.push(o) } setState(state){ this.state = state this.Observer.forEach(o=>{ o.update(this) }) } } let baby = new Observed('宝宝') let dad = new Observer('爸爸') let mom = new Observer('妈妈') // 添加观察者 baby.addObserver(dad) baby.addObserver(mom) // 设置状态 baby.setState('不开心') baby.setState('开心') 复制代码
用来解决异步
Promise 是一个天生的类 需要传入一个函数 默认会立即执行
有三种状态 ,成功(resolve) ,失败(reject), 等待
let a = new Promise((resolve, reject) => { // 这两个方法可以更改promise 状态 // resolve()如果是这样 下面的输出为 undefined resolve('成功') // reject('失败') }) a.then((data)=>{ console.log(data) // 成功 },(err)=>{ console.log(err) // 失败 }) 复制代码
resolve,reject 这两个方法可以改变状态。如果是 resolve
,则走then
的第一个函数,reject
走then
的第二个函数。并且都将参数传入。
**注意:**走成功了就不可以走失败,反之亦然
明白了基本用法,我们开始模仿一下Promise
。这里使用ES6
语法来模仿。
首先,需要就收一个executor
,是一个函数。立即执行,有三那种状态,里面还有resolve
,reject
两个参数,这两个参数是函数,需要接收两个参数。同时promise
还有then
方法
// promise 同步 // 三种状态的定义 const Pending = 'PENDING' const Success = 'SUCCESS' const Error = 'Error' // promise 的实现 class WritePromise { constructor(fn) { // 初始化 this.state = Pending // 状态初始化 this.value = undefined // 成功信息 this.err = undefined // 错误信息 let resolve = (value)=>{ if (this.state === Pending){ this.value = value this.state = Success } } let reject = (err)=>{ if (this.state === Pending){ this.value = err this.state = Error } } // 可能会出错 try { fn(resolve,reject) // 立即执行 }catch (e) { console.log(e) // 如果内部出错 直接交给reject 方法向下传递 reject(e) } } then(onfulfilled,onrejected){ switch (this.state) { case Success: onfulfilled(this.value) break case Error: onrejected(this.err) break } } } // export default WritePromise 浏览器端 module.exports = WritePromise 复制代码
在new的过程中,执行constructor
,传入的 resolve
orreject
,进行赋值和状态改变。然后then
方法更具 state
的状态进行不同的操作。onfulfilled
and onrejected
是传入的操作函数
为什么要加try catch
在使用过程中,不仅仅只有reject
可以接收错误,也可以手动抛出错误。这样就reject
捕获不到错误。 所以要加上 try catch 。 保证可以正常运行
let WritePromise = require('./WritePromise') let promise = new WritePromise((resolve, reject) => { // 1. resolve('成功') // 2. // reject('失败') }) promise.then((data) => { // onfulfilled 成功 console.log(data) }, (err) => { // onrejected 失败 console.log(err) }) // 输出 1. 成功 2. 失败 复制代码
大家会发现。如果在resolve
orreject
,执行异步代码(例如定时器)。会发现没有结果。这是因为我们刚才写的都是同步代码。现在要改一下,改成异步的
这时候就用到我们前面的知识了,发布订阅模式
首先,我们应该知道在constructor
中传入的fn
,如果加上定时器的话,它的状态state
不会发生任何改变。也就是一直处于等待状态
, 所以并不会执行then
里面的函数。所以我们应该考虑一下当他处于等待
的时候。是不是应该吧传入的函数存储起来,等到上面执行resolve
orreject
的时候,再把这个函数执行。
// promise 异步 const Pending = 'PENDING' const Success = 'SUCCESS' const Error = 'Error' class WritePromiseAsync { constructor(fn) { this.state = Pending this.value = undefined this.err = undefined // 回调函数的存储 this.SuccessCal = [] this.ErrorCal = [] let resolve = (value)=>{ if (this.state === Pending){ this.value = value this.state = Success // 对回调函数进行变量 然后执行 this.SuccessCal.forEach((fn)=>fn()) } } let reject = (err)=>{ if (this.state === Pending){ this.value = err this.state = Error this.ErrorCal.forEach((fn)=>fn()) } } // 可能会出错 try { fn(resolve,reject) // 立即执行 }catch (e) { console.log(e) // 如果内部出错 直接交给reject 方法向下传递 reject(e) } } then(onfulfilled,onrejected){ switch (this.state) { case Success: onfulfilled(this.value) break case Error: onrejected(this.err) break case Pending: this.SuccessCal.push(()=>{ // 为什么要这样写 因为这样可以做一些逻辑 AOP // 这里面可以做一些逻辑 onfulfilled(this.value) }) this.ErrorCal.push(()=>{ onrejected(this.err) }) break } } } module.exports = WritePromiseAsync 复制代码
在顺一遍。 创建对象之后,调用then
方法, 代码开始执行,执行到then
的时候,发现没有对应的状态改变,就先把它存储起来。等到定时器结束之后,在把所有的函数都执行一次
then
)// 第二点的 代码解释 let b = new Promise((resolve, reject) => { resolve('data') }).then((data)=>{ data = data + '132456' // then可以返回一个值,如果是普通值。就会走到下一个then 的成功中 return data }).then((data)=>{ console.log(data) // 输出 data132456 }) 复制代码
如果返回的不是普通值,是promise,则会使用这个promise的结果
let b = new Promise((resolve, reject) => { resolve('data') }).then((data)=>{ data = data + '132456' return data }).then(()=>{ return new Promise((resolve, reject) => { resolve('我是promise 的返回') // 如果返回的是一个promise,那么会采用这个promise的结果 }) }).then((data)=>{ console.log(data) // 输出 我是promise 的返回 }) 复制代码
用来捕获 最近的且没有捕获的错误
let b = new Promise((resolve, reject) => { reject('data') }).then().catch(err=>{ // 捕获错误 捕获最近的没有捕获的错误 console.log(err+'catch') // datacatch // 注意 返回的也是undefined }) 复制代码
上述走的是成功
,失败也一样。但会有一个小坑。
let b = new Promise((resolve, reject) => { resolve('data') }).then(()=>{},err=>{ console.log(err) // 在失败函数中如果返回的是一个普通值,也会走下一次then的成功中 // return undefined 相当于返回了一个这个 }).then((data)=>{ console.log(data+'success') // 这个会走 成功的值 输出 underfinedsuccess },(err)=>{ console.log(err+'err') }) 复制代码
特别注意,这里会经常有遗漏。
接着上次的WritePromiseAsync
原版做法中,当连续调用then
方法的时候,会把上一次的结果传递给下一个then
。
上面说过每次调用then
方法会返回一个promise
实例。所以,我们需要在调用then
方法的时候返回一个promise
的实例,并且接收到then
方法的结果。在传递给这个promise
// 多余的我就不写了,主要写差异化 的 then方法 then(onfulfilled, onrejected) { let promise2 = new ChainPromise((resolve, reject) => { let x switch (this.state) { case Success: x = onfulfilled(this.value) resolve(x) break case Error: x = onrejected(this.value) reject(x) break case Pending: this.SuccessCal.push(() => { try { let x = onfulfilled(this.value) resolve(x) } catch (e) { reject(e) } }) this.ErrorCal.push(() => { try { let x = onrejected(this.err) reject(x) } catch (e) { reject(e) } }) break } }) return promise2 } 复制代码
注意,调用的时候要把 then
的两个函数都要写上,否则会报错(还没有处理)
这样过后 就可以实现 多次then方法传递结果了
说一下上面得哪个x
,我们是直接把它返回给对应得处理方法,如果x
是一个promise
呢? 按照原版得来说。我们应该把这个promise
的结果作为返回值来继续传递。所以我们应该对这个x
进行处理
创建一个方法solveX
,来处理x
。
function solveX(promise2, x, resolve, reject) { if (promise2 === x){ return reject(new TypeError('引用本身')) } if ((typeof x === 'object' && x != null)|| typeof x === 'function'){ // 处理promise try { let then = x.then if (typeof then === 'function'){ // 只能认定他是promise了 then.call(x,(data)=>{ console.log(data) resolve(data) },(err)=>{ reject(err) }) } else { resolve(x) } } catch (e) { reject(e) // 取值失败 走err } }else { // 是一个普通值 resolve(x) } } 复制代码
为什么要把promise2
传进来呢? 因为如果 x
就是promise2
呢?则会是一个死循环。
对x
进行判断,如果是普通值,直接返回就可以了。如果不是,我们取then
方法(注意是方法,不是结果). 如果有这个方法,我们就认定他是一个promise
(可能有人会说如果then
是一个空方法呢?,那也只能认定了,我们最多只能做到这种程度的判断了。)
注意then
的this 指向问题
try { x = onfulfilled(this.value) resolvePromise(promise2, x, resolve, reject) // 需要用x 来比较promise2的值 // resolve() } catch (e) { // 一旦出错,走下一个promise 的错误处理方法 reject(e) } 复制代码
如果直接传入promise2
的话,因为是同步的过程,在创建的时候promise2
还没有生成,所以会报错。这时候我们可以加一个定时器,把它变成异步。这就解决了这个问题
then(onfulfilled, onrejected) { let promise2 = new ChainPromise((resolve, reject) => { let x switch (this.state) { case Success: setTimeout(() => { // 如果不加定时器,promise2获取不到 try { x = onfulfilled(this.value) resolvePromise(promise2, x, resolve, reject) // 需要用x 来比较promise2的值 // resolve() } catch (e) { // 一旦出错,走下一个promise 的错误处理方法 reject(e) } }, 0) // 实现之后要判断 X 如果x是一个普通值,就正常返回。如果是一个promise 则把promise的执行结果作为参数传递给 相应的处理函数 break case Error: setTimeout(() => { try { x = onrejected(this.err) // reject(x) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) break case Pending: this.SuccessCal.push(() => { try { let x = onfulfilled(this.value) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) this.ErrorCal.push(() => { try { let x = onrejected(this.err) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) break } }) return promise2 } 复制代码
注意,即使写的是0
,也不会立即执行。
上面我们写了一个方法来处理promise
,只需要进行一个递归就可以解决
function resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) { return reject(new TypeError('引用本身')) } if ((typeof x === 'object' && x != null) || typeof x === 'function') { // 处理promise try { let then = x.then if (typeof then === 'function') { then.call(x, (data) => { // resolve(data) 将data重新放入这个函数。直到是一个普通值再进行返回 resolvePromise(promise2, data, resolve, reject) }, (err) => { // reject(err) resolvePromise(promise2, err, resolve, reject) }) } else { resolve(x) } } catch (e) { reject(e) // 取值失败 走err } } else { // 是一个普通值 resolve(x) } } 复制代码
then(onfulfilled, onrejected) { onfulfilled = typeof onfulfilled === 'function'?onfulfilled:v=>v onrejected = typeof onrejected === 'function'?onrejected:err=>{throw err} ........ } 复制代码
将两个函数进行判断。如果不是函数,默认赋一个函数
function resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise #<Promise>--')) } let called // 添加一个变量进行控制 if ((typeof x === 'object' && x != null) || typeof x === 'function') { try { let then = x.then if (typeof then === 'function') { then.call(x, y => { if (called) return called = true resolvePromise(promise2, y, resolve, reject) }, r => { if (called) return // 如果发现被调用过 直接return called = true reject(r) }) } else { resolve(x) } } catch (e) { if (called) return called = true reject(e) } } else { resolve(x) } } 复制代码
// promise 链式调用的实现 const PENDING = 'PENDING' const RESOLVED = 'RESOLVED ' const REJECTED = 'REJECTED' function resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise #<Promise>--')) } let called if ((typeof x === 'object' && x != null) || typeof x === 'function') { try { let then = x.then if (typeof then === 'function') { then.call(x, y => { if (called) return called = true resolvePromise(promise2, y, resolve, reject) }, r => { if (called) return called = true reject(r) }) } 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.SuccessCal = [] this.ErrorCal = [] let resolve = value => { if (this.status === PENDING) { this.value = value this.status = RESOLVED this.SuccessCal.forEach(fn => fn()) } } let reject = reason => { if (this.status === PENDING) { this.reason = reason this.status = REJECTED this.ErrorCal.forEach(fn => fn()) } } try { executor(resolve, reject) } catch (e) { reject(e) } } then(onRESOLVED, onrejected) { onRESOLVED = typeof onRESOLVED === 'function' ? onRESOLVED : v => v onrejected = typeof onrejected === 'function' ? onrejected : err => { throw err } let promise2 = new Promise((resolve, reject) => { if (this.status === RESOLVED) { setTimeout(() => { // 如果不加定时器,promise2获取不到 try { let x = onRESOLVED(this.value) resolvePromise(promise2, x, resolve, reject) // 需要用x 来比较promise2的值 } catch (e) { // 一旦出错,走下一个promise 的错误处理方法 reject(e) } }, 0) // 实现之后要判断 X 如果x是一个普通值,就正常返回。如果是一个promise 则把promise的执行结果作为参数传递给 相应的处理函数 } if (this.status === REJECTED) { setTimeout(() => { try { let x = onrejected(this.reason) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) } if (this.status === PENDING) { this.SuccessCal.push(() => { // 为什么要这样写 因为这样可以做一些逻辑 // 这里面可以做一些逻辑 setTimeout(() => { try { let x = onRESOLVED(this.value) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) }) this.ErrorCal.push(() => { setTimeout(() => { try { let x = onrejected(this.reason) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) }) } }) return promise2 } } // 测试 需要测试再添加 Promise.defer = Promise.deferred = function () { let dfd = {} dfd.promise = new Promise((resolve, reject) => { dfd.resolve = resolve dfd.reject = reject }) return dfd } module.exports = Promise 复制代码
这个是测试工具的github
安装之后, 执行
npx promises-aplus-tests promise.js
为什么是npx
? 我没有全局安装
全部通过