知足如下条件之一:git
定义: 有权访问另外一个函数做用域中变量的函数(来源红宝书
)github
柯里化(Currying),把接受多个参数的函数转换成接受一个单一参数的函数编程
let add = function(x) {
return function(y) {
return x + y
}
}
add(3)(4) // 7
复制代码
实际开发若是须要用到 柯里化,推荐使用 lodash.curry 设计模式
typeof
没法判断 对象 类型数组
constructor
判断 是谁构造出来的promise
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
? 我没有全局安装
所有经过