一、高阶函数
二、柯里化函数
三、观察者模式
四、手写Promise
Promise/A+规范
Promise为何产生?
Promise优缺点?
Promise特点?
实现一个简单Promise
进一步实现一个简单Promise
实现一个完整的promise库
测试promise
实现resolve、reject、catch、finally
实现race、all
一、高阶函数 1.什么是高阶函数? 1.参数是函数
1 2 3 function say (cb ) { cb () }
2.函数返回函数
1 2 3 function say () { return function () {} }
2.高阶函数应用场景? 需要在公共方法前调用其他方法
1 2 3 4 function say ( ) { console .log('say' ) }
1 2 3 4 5 6 7 8 9 10 11 12 Function .prototype.before = function (cb ) { const that = this return function ( ) { cb() that() } } const beforeSay = say.before(function ( ) { console .log('beforeSay' ) }) beforeSay()
可以换成()=>
:
1 2 3 4 5 6 Function .prototype.before = function (cb ) { return () => { cb() this () } }
实现传参:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function say (a, b ) { console .log('say' , a, b) } Function .prototype.before = function (cb ) { return (...args ) => { cb() this (...args) } } const beforeSay = say.before(function ( ) { console .log('beforeSay' ) }) beforeSay('hello' , 'world' )
箭头函数无arguments。...
的意义:return (...args)剩余运算符
,this(...args)展开运算符
。
二、柯里化函数 1.判断变量类型的方法 1.typeof 判断不出对象类型
2.constructor 谁构造出来的
1 2 [] .constructor ({}).constructor
3.inistanceof 谁是谁的实例 proto
1 2 [] instanceof Array // true ({}) instanceof Object // true
4.Object.prototype.toString.call()
1 2 Object.prototype .toString .call ([] ) Object.prototype .toString .call ({})
Array.isArray的原理:
1 2 3 Array .myIsArray = function (o ) { return Object .prototype.toString.call(Object (o) === '[object Array]' ); }
2.柯里化函数 1.类型判断
1 2 3 4 5 6 function isType(value , type ) { return Object . prototype.toString.call(value) === `[object $ {type }] ` } isType([], "Array" ) isType({}, "Object" )
2.柯里化函数实现类型判断
1 2 3 4 5 6 7 8 9 function isType (type ) { return function (value ) { return Object .prototype.toString.call(value) === `[object ${type } ]` } } const isArray = isType('Array' )const isObject = isType('Object' )isArray([]) isObject({})
3.柯里化函数实现柯里化方法 实现一个currying方法,使其成立?
1 2 3 4 5 6 7 8 9 10 11 function sum (a,b,c,d,e,f) const r = currying (sum) (1,2) (3,4) (5) (6) function currying ()
实现如下:
1 2 3 4 5 6 7 8 9 10 11 const currying = (fn, arr = []) => { const len = fn.length return function (...args ) { arr = [...arr, ...args] if (arr.length < len) { return currying(fn, arr) } else { return fn(...arr) } } }
4.currying方法同样作用于isType
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function isType (value, type ) { return Object .prototype.toString.call(value) === `[object ${type } ]` } isType([], "Array" ) function isType (type ) { return function (value ) { return Object .prototype.toString.call(value) === `[object ${type } ]` } } const isArray = isType('Array' )isArray([]) const isArray = currying(isType)('Array' )isArray([])
三、观察者模式 1.什么是闭包? 函数定义和执行不在同一个作用域下。 举例:同步获取两个txt的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 let fs = require('fs' )let school = {}let index = 0 const cb = () => { if (++index === 2 ) { console.log (school) } } fs.readFile('./name.txt' , 'utf-8' , function (err, data) { school.name = data cb () }) fs.readFile('./age.txt' , 'utf-8' , function (err, data) { school.age = data cb () }) // 输出{ name: 'wuwei' , age: '28' }
使用闭包:
1 2 3 4 5 6 7 8 9 10 11 const cb = after(2 , function ( ) { console .log(school) }) function after (times, callback ) { return function ( ) { if (--times === 0 ) { callback() } } }
2.订阅发布模式 emit-on emit:订阅,数组中的方法依次执行 on:发布,方法添加到数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 let fs = require ('fs' )let school = {}fs.readFile('./name.txt' , 'utf-8' , function (err, data ) { school.name = data event.emit() }) fs.readFile('./age.txt' , 'utf-8' , function (err, data ) { school.age = data event.emit() }) let event = { arr : [], on (fn ) { this .arr.push(fn) }, emit ( ) { this .arr.forEach(fn => fn()) } } event.on(function ( ) { if (Object .keys(school).length === 2 ) { console .log(school) } })
订阅发布无直接关联,靠中介来完成。 观察者模式有直接关联。
3.观察者模式 有观察者、被观察者。 观察者放到被观察者中,被观察者发生改变通知观察者。 内部用到发布订阅
模式,收集观察者。
举例:我和我媳妇儿观察小宝宝的心里状态变化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class Subject { constructor (name ) { this .name = name this .state = '开心的' this .observers = [] } attach (o ) { this .observers.push(o) } setState (newState ) { this .state = newState this .observers.forEach(o => o.update(this )) } } class Observer { constructor (name ) { this .name = name } update (o ) { console .log('当前' ,this .name,'被通知了' ,',当前小宝宝的状态是' ,o.state) } } let baby = new Subject('小宝宝' )let parent = new Observer('爸爸' )let monther = new Observer('妈妈' )baby.attach(parent) baby.attach(monther) baby.setState('被欺负了' )
四.手写Promise 1.Promise/A+规范 Promise都通过这个规范来实现。 ES6内部已经实现、IE都不支持Promise,需要polyfill,es6-promise。 地址:https://promisesaplus.com
2.Promise为何产生? 解决异步问题。
3.Promise优缺点? 优点: 1.解决多个异步请求最终获取同步结果 Promise.all
2.解决链式异步请求问题,上一个的输出是下一个的输入 使用Promise链式调用
缺点:还是基于回调实现的
4.Promise特点? 1.Promise有三种状态:成功态、失败态、等待态 2.成功fulfilled,失败rejected、等待pending(不成功也不失败) 3.用户自己定义成功失败原因 4.promise构造方法会立即执行 5.成功后不执行失败,失败后不执行成功 6.出异常也会走失败回调 7.promise实例有then方法,一个参数是成功回调,一个参数是失败回调
1 2 3 4 5 6 7 8 9 10 let promise = new Promise ((resolve, reject) => { resolve('success' ) reject('error' ) throw new Error ('error' ) }) promise.then ((rst) => { console .log(rst) },(err) => { console .error('fail' , err) })
5.实现一个简单Promise 基于Promise上面提到的7个特点来写Promise:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 const RESOLVE = 'fulfilled'const REJECT = 'rejected'const PENDING = 'pending'class Promise { constructor(executor) { this.state = PENDING this.value = undefined this.reason = undefined let resolve = (value) => { if (this.state === PENDING) { this.value = value this.state = RESOLVE } } let reject = (err) => { if (this.state === PENDING) { this.reason = err this.state = REJECT } } try { executor(resolve, reject) } catch (error) { reject(error) } } then(on Fulfilled, on Rejected) { if (this.state === RESOLVE) { on Fulfilled(this.value) } if (this.state === REJECT) { on Rejected(this.reason) } } }
6.进一步实现一个简单Promise Promise除了上面7个特点外,还有个重要特点:一个prmoise实例可以多次then,当前状态如果是pending时,需要将成功回调、失败回调存放起来,稍后调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 let promise = new Promise ((resolve, reject) => { console .log('1' ) setTimeout (() => { resolve() }) }) promise.then (() => { console .log('2' ) },(err) => { console .log('3' ) }) console .log('4' )promise.then (() => { console .log('5' ) },(err) => { console .log('6' ) }) console .log('7' )
执行结果:1、4、7、2、5
为了依次执行then方法的成功和失败回调,使用订阅发布模式将其存起来。
完整Promise实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 const RESOLVE = 'fulfilled'const REJECT = 'rejected'const PENDING = 'pending'class Promise { constructor(executor) { this.state = PENDING this.value = undefined this.reason = undefined this.on ResolvedCallbacks = [] this.on RejectedCallbacks = [] let resolve = (value) => { if (this.state === PENDING) { this.value = value this.state = RESOLVE this.on ResolvedCallbacks.for Each(fn=>fn()) } } let reject = (err) => { if (this.state === PENDING) { this.reason = err this.state = REJECT this.on RejectedCallbacks.for Each(fn=>fn()) } } try { executor(resolve, reject) } catch (error) { reject(error) } } then(on Fulfilled, on Rejected) { if (this.state === RESOLVE) { on Fulfilled(this.value) } if (this.state === REJECT) { on Rejected(this.reason) } if(this.state === PENDING) { this.on ResolvedCallbacks.push(() => { on Fulfilled(this.value) }) this.on RejectedCallbacks.push(() => { on Rejected(this.reason) }) } } }
7.实现一个完整的promise库 除了上面特点,promise还有以下特点:
1.prmoise成功和失败的回调的返回值,可以传递到外层的then
2.返回值是普通值、promise、出错
普通值,走下一次成功 出错,走下一次失败
值promise,采用promise状态,成功走成功,失败走失败
错误处理 如果离自己最近的then,没出错,会向下找
3.每次执行promise,then返回一个”新的promise“
4.then需要实现透传
5.兼容其他promise …
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 const RESOLVE = 'fulfilled' const REJECT = 'reject' const PENDING = 'pending' const 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) },e => { if (called) return ; called = true ; reject(e) }) } else { resolve(x) } } catch (e) { if (called) return ; called = true ; reject(e) } } else { resolve(x) } } class Promise { constructor (executor ) { this .state = PENDING this .value = undefined this .reason = undefined this .onFulfilledCallbacks = [] this .onRejectedCallbacks = [] let resolve = (value ) => { if (value instanceof Promise ){ return value.then(resolve,reject); } if (this .state === PENDING) { this .value = value this .state = RESOLVE this .onFulfilledCallbacks.forEach(fn => fn()) } } let reject = (reason ) => { if (this .state === PENDING) { this .reason = reason this .state = REJECT this .onRejectedCallbacks.forEach(fn => fn()) } } try { executor(resolve, reject) } catch (e) { reject(e) } } then (onFulfilled, onRejected ) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v; onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err } let promise2 = new Promise ((resolve, reject )=> { if (this .state === RESOLVE) { setTimeout (()=> { try { let x = onFulfilled(this .value) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } },0 ) } if (this .state === REJECT) { setTimeout (()=> { try { let x = onRejected(this .reason) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } },0 ) } if (this .state === PENDING) { this .onFulfilledCallbacks.push(()=> { setTimeout (()=> { try { let x = onFulfilled(this .value) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } },0 ) }) this .onRejectedCallbacks.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
8.测试promise promise的延迟对象,将resolve 和 reject放到一个对象中:
1 2 3 4 5 6 7 8 Promise .defer = Promise .deferred = function ( ) { let dfd = {}; dfd.promise = new Promise ((resolve,reject )=> { dfd.resolve = resolve; dfd.reject = reject; }) return dfd }
安装npm install promises-aplus-tests -g
; 运行promises-aplus-tests Promise.js
进行测试。
运行测试结果,如果有错误或未完善,则抛出需要更改的点:
测试成功:
9.实现resolve、reject、catch、finally Promise.resolve:快速创建一个成功的promise
Promise.reject:快速创建一个失败的promise
1 2 3 4 5 6 7 8 9 10 11 12 13 class Promise { ... static resolve (data ) { return new Promise ((resolve,reject )=> { resolve(data); }) } static reject (reason ) { return new Promise ((resolve,reject )=> { reject(reason); }) } }
catch:catch的本质就是then方法,表示的是没有成功的失败函数
1 2 3 Promise .prototype.catch = function (errCallback ) { return this .then(null ,errCallback) }
finally:finally的本质就是then方法,表示的是无论如何都会执行
1 2 3 4 5 6 7 Promise .prototype.finally = function(callback) { return this .then ((value) => { return Promise .resolve(callback()).then (() => value) },(reason) => { return Promise .reject(callback()).then (() => {throw reason}) }) }
10.实现race、all Promise.race:快速执行所有promise,哪个快,返回哪个的结果
Promise.all:快速执行所有promise,全部成功才成功,返回所有结果数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class Promise { ... static race (promises ) { return new Promise ((resolve,reject )=> { for (let i = 0 ; i < promises.length; i++) { let result = promises[i] if (typeof result.then === 'function' ){ result.then(resolve,reject) }else { resolve(result) } } }) } static all (promises ) { return new Promise ((resolve,reject )=> { let arr = [] let index = 0 const processData = (key, value ) => { arr[key] = value if (++index === promises.length) { resolve(arr) } } for (let i = 0 ; i < promises.length; i++) { let result = promises[i] if (typeof result.then === 'function' ){ result.then((data )=> { processData(i,data) },reject) }else { processData(i,result) } } }) } }