函数式概念test1.2
Promise 模拟
一 、setTimeout 改写promise
setTimeout(function() {
var a = 'hello'
setTimeout(() => {
var b = 'lagou'
setTimeout(() => {
var c = 'I ❤ U'
// console.log(a + b + c);
}, 10);
}, 10);
}, 10)
let pro = new Promise((resolve, reject) => {
resolve('hello')
})
方案一:
pro.then(value => {
// console.log(value);
return value
}).then(value => {
// console.log(value)
return value + 'logou'
}).then(value => {
// console.log(value);
return value + 'I ❤ U'
}).then(value => {
console.log(value);
方案二:
function a() {
return new Promise((resolve, reject) => {
resolve('hello')
})
}
function b(data) {
return new Promise((resolve, reject) => {
resolve(data + 'lagou')
})
}
function c(data) {
return new Promise((resolve, reject) => {
resolve(data + 'I ❤ U')
})
}
a().then(value => { return b(value) })
.then(value => { return c(value) })
.then(value => { console.log(value); })
二 、基于lodash的联系
const fp = require('lodash/fp')
// 数据
// horsepower 马力,doller_value 价格, in_stock 库存
const cars = [{
name: 'Ferrari FF',
horsepower: 660,
doller_value: 700000,
in_stock: true
}, {
name: 'Spyker C12 Zagato',
horsepower: 650,
doller_value: 648000,
in_stock: false
}, {
name: 'Jaguar XKR-S',
horsepower: 550,
doller_value: 132000,
in_stock: false
}, {
name: 'Audi R8',
horsepower: 525,
doller_value: 114200,
in_stock: false
}, {
name: 'Aston Martin One-77',
horsepower: 750,
doller_value: 1850000,
in_stock: true
}, {
name: 'Pagani Huayra',
horsepower: 700,
doller_value: 1300000,
in_stock: false
}]
- 使用函数组合fp.flowRight()实现以下函数:
let isLastInStock = function(cars) {
// 获取最后一条数据
let last_car = fp.last(cars)
// 获取最后一条数据的in_stock属性值
return fp.prop('in_stock', last_car)
}
console.log(isLastInStock(cars)); //false
let isLastInStockEl = fp.flowRight(fp.prop('in_stock'), fp.last)
console.log(isLastInStockEl(cars)); //false
- 使用fp.flowRight()、 fp.prop() 和fp.first() 获取第一个car的name:
let carsFirstName = fp.flowRight(fp.prop('name'), fp.first)
console.log(carsFirstName(cars)); //Ferrari FF
- 使用帮助函数_average 重构averageDollarValue,使用函数组合的方式实现
let _average = function(xs) {
return fp.reduce(fp.add, 0, xs) / xs.length
} //不改动
let averageDollarValue = function(cars) {
let doller_values = fp.map(function(car) {
return car.doller_value
}, cars)
return _average(doller_values)
}
console.log(averageDollarValue(cars)); //790700
let averageDollarValueEl = fp.map(item => item.doller_value)
let combinationFn = fp.flowRight(_average, averageDollarValueEl)
console.log(combinationFn(cars)) //790700
- 使用flowRight()写一个sanitizeNames()函数,返回一个下划线连接的小写字符串, 把数组中的name转换为这种形式:例如:sanitizeNames([“Hello World”])=>[“hello_world”]
let _underscore = fp.replace(/\W+/g, '_') //无需改动,并在sanitizeNames中使用它
let sanitizeNames = fp.flowRight(_underscore, fp.lowerCase, fp.startCase)
console.log(sanitizeNames(['Hello World'])); //hello_world
三 、 基于下面提供的代码,完成后续四个练习
supports.js 为class封装类,已提供
// supports.js
class Container {
static of(value) {
return new Container(value)
}
constructor(value) {
this._value = value
}
map(fn) {
return Container.of(fn(this._value))
}
}
class Maybe {
static of(x) {
return new Maybe(x)
}
isNothing() {
return this._value === null || this._value === undefined
}
constructor(x) {
this._value = x
}
map(fn) {
return this.isNothing() ? this : Maybe.of(fn(this._value))
}
}
module.exports = { Maybe, Container }
- 使用fp.add(x,y)和fp.map()创建一个能让functor里的值增加的函数ex1
const fp = require('lodash/fp')
const { Maybe, Container } = require('./support')
let maybe = Maybe.of([5, 6, 1])
// let container = Container.of([5, 6, 1])
let ex1 = () => {
// 你需要实现的函数
return maybe.map(x => {
return fp.map(fp.add(2), x)
})
}
console.log("ex1", ex1()); //ex1 Maybe { _value: [ 7, 8, 3 ] }
console.log("maybe", maybe); //maybe Maybe { _value: [ 5, 6, 1 ] }
- 实现一个函数ex2,能够使用fp.first获取列表的第一个元素
const fp = require('lodash/fp')
const { Maybe, Container } = require('./support')
let xs = Container.of(['do', 'ray', 'me', 'fa', 'so', 'la', 'ti', 'do'])
let ex2 = () => {
// 需要实现
return xs.map(x => {
return fp.first(x)
})._value
}
let ex2 = () => xs.map(fp.first)._value
console.log("ex2", ex2()); //ex2 do
- 实现一个函数ex3,使用safeProp 和fp.first找到user的名字的首字母
const fp = require('lodash/fp')
const { Maybe, Container } = require('./support')
let safeProp = fp.curry(function(x, o) {
return Maybe.of(o[x])
})
let user = { id: 2, name: 'Albert' }
let ex3 = function(user) {
return safeProp('name', user).map(x => {
return fp.first(x)
})._value
}
console.log(ex3(user)); //A
- 使用Maybe 重写ex4, 不要有if 语句
const fp = require('lodash/fp')
const { Maybe, Container } = require('./support')
let ex4 = function(n) {
if (n) {
return parseInt(n)
}
}
let ex4 = (e) => {
return Maybe.of(parseInt(e))._value
}
console.log(ex4("5")); //5
四 、手写promsie源码(尽量还原promise的api),注释的方式描述思路和原理
MyPromise.js 为封装promise
// Promise 模擬
// 执行状态
const PENDDING = 'pendding' //等待
const FUILEED = 'fuilleed' //成功
const REJECT = 'reject' //失败
class MyPromise {
status = PENDDING //对象内的状态初始化
value = undefined //回调成功初始值
reason = undefined //回调失败初始值
successCallback = [] //成功的回调
failCallback = [] //失败的回调
constructor(excutor) { //内置生成器,生成一个处理成功和失败的调用函数(resolve,reject)
try { //执行器错误捕获
excutor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
resolve = value => { //成功的值
if (this.status !== PENDDING) { //判断执行状态是否是等待状态,等待则登出
return
}
this.status = FUILEED //状态赋值,状态一旦确定不可更改
this.value = value //回调参数赋值
while (this.successCallback.length) {
this.successCallback.shift()()
}
// this.successCallback && this.successCallback(this.value) //回调函数传参
}
reject = reason => { //失败的值(原因)
if (this.status !== PENDDING) {
return
}
this.status = REJECT
this.reason = reason
while (this.failCallback.length) {
this.failCallback.shift()()
}
// this.failCallback && this.failCallback(this.reason)
}
static resolve(value) {
if (value instanceof MyPromise) {
return value
} else {
return new MyPromise(resolve => resolve(value))
}
}
static all(arr) { //all()处理异步并发,限定执行顺序对应执行结果
// 获取传入数组,定义结果容器,定义异步等待下标
let result = []
let index = 0;
return new MyPromise((resolve, reject) => {
function saveArr(key, value) {
result[key] = value //存入执行结果于数组容器
index++ //所有的遍历记录
if (index == arr.length) { //当记录值与数组下标相等,表示遍历完毕数组所有值
resolve(result) //回调这个返回数组结果的容器
}
}
for (let i = 0; i < arr.length; i++) {
// 遍历传参数组,判断每个当前值是否是promise对象
// 如果是则当前值的回调函数结果存入数组容器(成功返回值,失败返回原因),
// 如果不是当前值存入数组容器
if (arr[i] instanceof MyPromise) {
arr[i].then(value => saveArr(i, value), reason => reject(reason))
} else {
saveArr(i, arr[i])
}
}
})
}
finally(callback) {
// this.then:获取当前的promise执行状态
return this.then(value => {
// callback返回的值通过resolve转换为promise
return MyPromise.resolve(callback()).then(() => value)
// callback()
// // 下一个then,传参
// return value
}, reason => {
return MyPromise.resolve(callback()).then(() => { throw reason })
// callback()
// return reason
})
}
then(successCallback, failCallback) { //成功或者失败的回调处理
// 判断thens是否参数可选:没有则返回这个函数,有则返回这个值
successCallback = successCallback ? successCallback : value => value;
failCallback = failCallback ? failCallback : reason => { throw reason }
// 生成一个promsie对象,返回输出结果,可以访问对象的属性及方法
let promiseEl = new MyPromise((resolve, reject) => {
// 状态判断,差异化返还执行结果
if (this.status == FUILEED) {
setTimeout(() => {
try { //then回调错误捕获
// successCallback(this.value)获取第一次返回值
// resolve(resetValue):重新把return的值交给resolve处理
// 用于链式调用,return新值
// 由于此事件会在成功/失败/等待都会执行,因此封装
let resetValue = successCallback(this.value)
// console.log("reset", resetValue); //reset 100
// resolve(resetValue)
resolvePromise(promiseEl, resetValue, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
} else if (this.status == REJECT) {
setTimeout(() => {
try {
let resetValue = failCallback(this.reason)
resolvePromise(promiseEl, resetValue, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
} else {
//异步处理:当入参是一个异步值时,需要临时将其存入返还
// 等待这两个函数被调用,执行resolve或者reject的successCallback&failCallback
this.successCallback.push(() => {
setTimeout(() => {
try { //then回调错误捕获
// successCallback(this.value)获取第一次返回值
// resolve(resetValue):重新把return的值交给resolve处理
// 用于链式调用,return新值
// 由于此事件会在成功/失败/等待都会执行,因此封装
let resetValue = successCallback(this.value)
// console.log("reset", resetValue); //reset 100
// resolve(resetValue)
resolvePromise(promiseEl, resetValue, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
})
this.failCallback.push(() => {
setTimeout(() => {
try {
let resetValue = failCallback(this.reason)
resolvePromise(promiseEl, resetValue, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
})
}
})
return promiseEl
}
catchEl(failCallback) {
// 传参为回调函数,通过then的两个处理方式(成功,失败),注册失败函数
return this.then(undefined, failCallback)
}
}
function resolvePromise(promiseEl, resetValue, resolve, reject) {
if (promiseEl === resetValue) { //捕获自己调用自己的情况
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (resetValue instanceof MyPromise) {
// resetValue.then(value => resolve(value), reason => reject(reason))
resetValue.then(resolve, reject)
} else {
resolve(resetValue)
}
}
module.exports = MyPromise
- Promise 基础调用、多次调用
const MyPromise = require('./promise_simulate')
let pro = new MyPromise((resolve, reject) => {
// setTimeout(() => {
resolve('Promise doing...')
// }, 2000);
})
// 多次调用
let pro = new MyPromise((resolve, reject) => {
// setTimeout(() => {
resolve('Promise doing...')
// }, 2000);
})
多次调用
pro.then(value => {
console.log('fulled', value);
}, reason => {
console.log('rejected', reason);
})
pro.then(value => {
console.log('fulled1', value);
}, reason => {
console.log('rejected1', reason);
})
pro.then(value => {
console.log('fulled2', value);
}, reason => {
console.log('rejected2', reason);
})
- 链式调用
// 链式调用
// 新建一个返回的promise
let pro = new MyPromise((resolve, reject) => {
// setTimeout(() => {
resolve('Promise doing...')
// }, 2000);
})
const resetPro = new MyPromise((resolve, reject) => {
resolve('resetPro')
})
pro.then(value => {
console.log(value);
return resetPro;
}).then(value => {
console.log(value);
})
- 捕获报错
let pro = new MyPromise((resolve, reject) => {
// setTimeout(() => {
// throw new Error('excutor error')
resolve('Promise doing...')
// }, 2000);
})
let p1 = pro.then(value => {
console.log(value);
// throw new Error('then error ')
return p1;
}, reason => {
console.log(reason);
})
p1.then(value => {
console.log(value);
}, reason => {
console.log('next then error', reason);
})
- 错误情况及捕获返回值
// 错误情况捕获返回值
let pro = new MyPromise((resolve, reject) => {
setTimeout(() => {
// throw new Error('excutor error')
resolve('Promise doing...')
// reject('Promise Fail...')
}, 2000);
})
pro.then(value => {
console.log(value);
return 'sss'
}, reason => {
console.log(reason);
return 1111
}).then(value => {
console.log(value);
})
- then 参数可选:没有,返回函数处理,有则返回 这个值
let pro = new MyPromise((resolve, reject) => {
resolve('Promise doing...')
})
pro.then().then().then(value => console.log(value))
- Promise.all() 处理异步并发解决:异步调用顺序返回异步结果(对应关系,无关异步)
let pro = new MyPromise((resolve, reject) => {
resolve('Promise doing...')
})
function pro1() {
return new MyPromise((resolve, reject) => {
resolve(100)
})
}
function pro2() {
return new MyPromise((resolve, reject) => {
resolve('work1')
})
}
MyPromise.all(['a', 'b', 'c', pro1(), pro2(), 'd']).then(values => console.log(values))
- promise.resolve():返回一个传入值,进行返回
如果是promise对象,则返回该值;如果不是对象,则返回该promise的resolve的调用
let pro = new MyPromise((resolve, reject) => {
resolve('Promise doing...')
})
function pro1() {
return new MyPromise((resolve, reject) => {
resolve(22)
})
}
MyPromise.resolve(100).then(value => console.log(value))
MyPromise.resolve(pro1()).then(value => console.log(value))
- promise.finally() prmoise是否成功都会调用的一个额外操作
let pro = new MyPromise((resolve, reject) => {
resolve('Promise doing...')
// reject('Promise failing...')
})
function pro1() {
return new MyPromise((resolve, reject) => {
// resolve(100)
setTimeout(() => {
reject(222)
}, 2000);
})
}
pro1().finally(() => {
console.log("finally");
return pro1()
}).then(value => {
console.log(value);
})
- Promise.catch():用来处理报错信息
function pro1() {
return new MyPromise((resolve, reject) => {
// resolve(100)
reject('fail')
})
}
pro1()
.then(value => console.log(value))
.catchEl(reason => console.log(reason))