内容将从js高级特性,奇技淫巧,高级特性等方面安排内容,包括多字段排序,经典递归,链式调用,class构造类型等等
1. 通用函数
- 1.1工厂函数
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("arg") :
typeof define === 'function' && define.amd ? define(['arg'], factory) : (global.plunginName = factory("arg"))
})(this, function () {
'use strict'
// 主要内容
return {}
})
- 1.2 canvas链式调用
window.Canvas2DContext = function (canvas) { //cavas链式调用
if (typeof canvas === 'string') {
canvas = document.getElementById(canvas)
}
if (!(this instanceof window.Canvas2DContext)) {
return new window.Canvas2DContext(canvas)
}
this.context = this.ctx = canvas.getContext('2d')
if (!window.Canvas2DContext.prototype.arc) {
Canvas2DContext.setup.call(this, this.ctx)
}
}
window.Canvas2DContext.setup = function () {
let methods = ['arc', 'arcTo', 'beginPath', 'bezierCurveTo', 'clearRect', 'clip',
'closePath', 'drawImage', 'fill', 'fillRect', 'fillText', 'lineTo', 'moveTo',
'quadraticCurveTo', 'rect', 'restore', 'rotate', 'save', 'scale', 'setTransform',
'stroke', 'strokeRect', 'strokeText', 'transform', 'translate'
]
let getterMethods = ['createPattern', 'drawFocusRing', 'isPointInPath', 'measureText', // drawFocusRing not currently supported
// The following might instead be wrapped to be able to chain their child objects
'createImageData', 'createLinearGradient',
'createRadialGradient', 'getImageData', 'putImageData'
]
let props = ['canvas', 'fillStyle', 'font', 'globalAlpha', 'globalCompositeOperation',
'lineCap', 'lineJoin', 'lineWidth', 'miterLimit', 'shadowOffsetX', 'shadowOffsetY',
'shadowBlur', 'shadowColor', 'strokeStyle', 'textAlign', 'textBaseline'
]
for (let m of methods) {
let method = m
Canvas2DContext.prototype = function () {
this.ctx.apply(this.ctx, arguments)
return this
}
}
for (let m of getterMethods) {
let method = m
Canvas2DContext.prototype = function () {
return this.ctx.apply(this.ctx, arguments)
}
}
for (let p of props) {
let prop = p
Canvas2DContext.prototype[prop] = function (value) {
if (value === undefined)
return this.ctx[prop]
this.ctx[prop] = value
return this
}
}
}
调用示例
let ctx = Canvas2DContext(document.getElementById('canvas'))
ctx.strokeStyle('rgb(30, 110, 210)').transform(10, 3, 4, 5, 1, 0).strokeRect(2, 10, 15, 20).context
let strokeStyle = Canvas2DContext(document.getElementById('canvas')).strokeStyle('rgb(50, 110, 210)').strokeStyle()
- 1.3 Date.format
Date.prototype.format = function (format) {
let o = {
"Y+": this.getFullYear() + '',
"M+": this.getMonth() + 1, //month MM
"D+": this.getDate(), //day DD
"h+": this.getHours(), //hour hh
"m+": this.getMinutes(), //minute mm
"s+": this.getSeconds(), //second ss
"Q+": Math.floor((this.getMonth() + 3) / 3), //quarter 季度 q
"c+": this.getMilliseconds(), //millisecond 毫秒 c
"W": ['一', '二', '三', '四', '五', '六', '日'][this.getDay() - 1] //week 星期
}
for (let k in o) {
if (new RegExp("(" + k + ")").test(format)) {
format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr((("" + o[k]).length >= 2 ? 2 : ("" + o[k]).length)))
}
}
return format
}
调用示例:
//new Date( year, month, date, hrs, min, sec)
//new Date() 参数可以为整数 也可以为字符串 但格式必须正确 example: new Date(2009,1,1) //正确 new Date("2009/1/1") //正确
//example new Date().format( "当前日期为:YYYY-MM-DD,星期W,为第Q季度,时间为:hh:mm:ss:c")
- 1.4 可终止的迭代器
function each(object, callback) {
/*可终止循环each方法*/
var type = (function (obj) {
switch (obj.constructor) {
case Object:
return 'Object';
break;
case Array:
return 'Array';
break;
case NodeList:
return 'NodeList';
break;
default:
return 'null';
break;
}
})(object);
// 为数组或类数组时, 返回: index, value
if (type === 'Array' || type === 'NodeList') {
// 由于存在类数组NodeList, 所以不能直接调用every方法
[].every.call(object, function (v, i) {
return callback.call(v, v, i) === false ? false : true;
});
}
// 为对象格式时,返回:key, value
else if (type === 'Object') {
for (var i in object) {
if (callback.call(object[i], object[i],i) === false) {
break;
}
}
}else{
}
}
- 1.5 多字段排序
function muchfieldarrsort(sarr, keys) {
// 多字段排序
/** sarr[]<Object>:原始数组。 keys[]<String>:要排序的多个字段,必须为数组*/
return sarr.sort(compare);
function compare(a, b, c = keys[0], i = 0) { //按合并类型递归排序
//var c = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : groupfieldarr[0];
//var i = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
if (a[c] == b[c]) { //等于的话进行判断是否还有后续字段需要排序,没有则返回0;有则递归进行后续字段排序处理。
if (i == (keys.length - 1)) { // 没有后续字段
i = 0;
return 0;
}
i += 1;
return compare(a, b, keys[i], i); //递归排序后续字段
} else if (a[c] > b[c]) {
return 1;
} else {
return -1;
}
}
}
- 1.6 全屏切换
function tooggleFullScreen(isFullscreen) {
isFullscreen = isFullscreen === undefined ? !(document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen) : isFullscreen
var de = document.documentElement
if (isFullscreen) { // 进入全屏
if (de.requestFullscreen) {
de.requestFullscreen()
} else if (de.mozRequestFullScreen) {
de.mozRequestFullScreen()
} else if (de.webkitRequestFullScreen) {
de.webkitRequestFullScreen()
}
} else { // 退出全屏
de = document
if (de.exitFullscreen) {
de.exitFullscreen()
} else if (de.mozCancelFullScreen) {
de.mozCancelFullScreen()
} else if (de.webkitExitFullscreen) {
de.webkitExitFullscreen()
}
}
}
- 1.7 节流函数
// 思路:在规定时间内只触发一次
function throttle(fn, delay) {
// 利用闭包保存时间
let prev = Date.now()
return function () {
let context = this
let arg = arguments
let now = Date.now()
if (now - prev >= delay) {
fn.apply(context, arg)
prev = Date.now()
}
}
}
调用示例
function fn() {
console.log('节流')
}
addEventListener('scroll', throttle(fn, 1000))
- 1.8 防抖函数
// 思路:在规定时间内未触发第二次,则执行
function debounce(fn, delay) {
// 利用闭包保存定时器
let timer = null
return function () {
let context = this
let arg = arguments
// 在规定时间内再次触发会先清除定时器后再重设定时器
clearTimeout(timer)
timer = setTimeout(function () {
fn.apply(context, arg)
}, delay)
}
}
调用示例
function fn() {
console.log('防抖')
}
addEventListener('scroll', debounce(fn, 1000))
- 1.9 柯里化函数
柯里化函数的定义: 将多参数的函数转换成单参数的形式。
柯里化函数实现的原理: 利用闭包原理在执行可以形成一个不销毁的作用域, 然后把需要预先处理的内容都储存在这个不销毁的作用域中, 并且返回一个最少参数函数。
第一种: 固定传入参数, 参数够了才执行
实现要点:
柯里化函数接收到足够参数后,就会执行原函数,那么我们如何去确定何时达到足够的参数呢?
柯里化函数需要记住你已经给过他的参数,如果没给的话,则默认为一个空数组。
接下来每次调用的时候,需要检查参数是否给够,如果够了,则执行fn,没有的话则返回一个新的 curry 函数,将现有的参数塞给他。
初步封装
var currying = function (fn) {
// args 获取第一个方法内的全部参数
var args = Array.prototype.slice.call(arguments, 1)
return function () {
// 将后面方法里的全部参数和args进行合并
var newArgs = args.concat(Array.prototype.slice.call(arguments))
// 把合并后的参数通过apply作为fn的参数并执行
return fn.apply(this, newArgs)
}
}
支持多参数传递封装
function progressCurrying(fn, args) {
var _this = this
var len = fn.length;
var args = args || [];
return function () {
var _args = Array.prototype.slice.call(arguments);
Array.prototype.push.apply(args, _args);
// 如果参数个数小于最初的fn.length,则递归调用,继续收集参数
if (_args.length < len) {
return progressCurrying.call(_this, fn, _args);
}
// 参数收集完毕,则执行fn
return fn.apply(this, _args);
}
}
- 1.10简单双向数据绑定
let obj = {}
let input = document.getElementById('input')
let span = document.getElementById('span')
// 数据劫持
Object.defineProperty(obj, 'text', {
configurable: true,
enumerable: true,
get() {
console.log('获取数据了')
},
set(newVal) {
console.log('数据更新了')
input.value = newVal
span.innerHTML = newVal
}
})
// 输入监听
input.addEventListener('keyup', function (e) {
obj.text = e.target.value
})
- 1.11 ajax
function ajax(options) {
// 请求地址
const url = options.url
// 请求方法
const method = options.method.toLocaleLowerCase() || 'get'
// 默认为异步true
const async = options.async
// 请求参数
const data = options.data
// 实例化
const xhr = new XMLHttpRequest()
// 请求超时
if (options.timeout && options.timeout > 0) {
xhr.timeout = options.timeout
}
// 返回一个Promise实例
return new Promise((resolve, reject) => {
xhr.ontimeout = () => reject && reject('请求超时')
// 监听状态变化回调
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
// 200-300 之间表示请求成功,304资源未变,取缓存
if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
resolve && resolve(xhr.responseText)
} else {
reject && reject()
}
}
}
// 错误回调
xhr.onerror = err => reject && reject(err)
let paramArr = []
let encodeData
// 处理请求参数
if (data instanceof Object) {
for (let key in data) {
// 参数拼接需要通过 encodeURIComponent 进行编码
paramArr.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
}
encodeData = paramArr.join('&')
}
// get请求拼接参数
if (method === 'get') {
// 检测url中是否已存在 ? 及其位置
const index = url.indexOf('?')
if (index === -1) url += '?'
else if (index !== url.length - 1) url += '&'
// 拼接url
url += encodeData
}
// 初始化
xhr.open(method, url, async)
// 发送请求
if (method === 'get') xhr.send(null)
else {
// post 方式需要设置请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8')
xhr.send(encodeData)
}
})
}
- 1.12 树形数据和平行数据互相转换
平行数据转嵌套树
function listToTree(tempData) {
// 删除所有的children,以防止多次调用
let map = {}; // 构建map
tempData.forEach(function (item) {
delete item.children;
map[item.id] = item; // 构建以id为键 当前数据为值
map["children"]=[]
});
let treeData = [];
tempData.forEach(child => {
const mapItem = map[child.pid]; // 判断当前数据的pid是否存在map中
if (mapItem) {
// 存在则表示当前数据不是最顶层的数据
// 注意: 这里的map中的数据是引用了tempData的它的指向还是arr,当mapItem改变时arr也会改变,踩坑点
(mapItem.children || (mapItem.children = [])).push(child); // 这里判断mapItem中是否存在child
} else {
// 不存在则是顶层数据
treeData.push(child);
}
});
return treeData;
}
树形数据转平行数据,运用参数缓存结果
function treeToList(data, pid = '',list = []) {
// 树形数据转换成平行数据
data.forEach((item, index) => {
list.push(Object.assign(item, { pid: }))
if (Array.isArray(item.children) && item.children.length) {
this.treeToList(item.children,item.id, list)
}
})
return list
}
- 1.13 精确计算
- 1.14 金额大写
function digitUppercase(money) {
// 汉字的数字
let cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
// 基本单位
let cnIntRadice = ['', '拾', '佰', '仟']
// 对应整数部分扩展单位
let cnIntUnits = ['', '万', '亿', '兆']
// 对应小数部分单位
let cnDecUnits = ['角', '分', '毫', '厘']
// 整数金额时后面跟的字符
let cnInteger = '整'
// 整型完以后的单位
let cnIntLast = '元'
// 最大处理的数字
let maxNum = 999999999999999.9999
// 金额整数部分
let integerNum
// 金额小数部分
let decimalNum
// 输出的中文金额字符串
// 分离金额后用的数组,预定义
let parts
let chineseStr = money < 0 ? '欠' : ''
money = (money + '').split('').filter((item, index) => {
return new RegExp('^[0-9.]$').test(item)
}).join('')
if (money === '') { return '' }
money = Math.abs(money) + ''
if (money >= maxNum) {
// 超出最大处理数字
return ''
}
if (money === 0) {
chineseStr = chineseStr + (cnNums[0] + cnIntLast + cnInteger)
return chineseStr
}
// 转换为字符串
if (money.indexOf('.') === -1) {
integerNum = money
decimalNum = ''
} else {
parts = money.split('.')
integerNum = parts[0]
decimalNum = parts[1].substr(0, 4)
}
// 获取整型部分转换
if (parseInt(integerNum, 10) > 0) {
let zeroCount = 0
let IntLen = integerNum.length
for (let i = 0; i < IntLen; i++) {
let n = integerNum.substr(i, 1)
let p = IntLen - i - 1
let q = p / 4
let m = p % 4
if (n === '0') {
zeroCount++
} else {
if (zeroCount > 0) {
chineseStr += cnNums[0]
}
// 归零
zeroCount = 0
chineseStr += cnNums[parseInt(n)] + cnIntRadice[m]
}
if (m === 0 && zeroCount < 4) {
chineseStr += cnIntUnits[q]
}
}
chineseStr += cnIntLast
}
// 小数部分
if (decimalNum !== '') {
let decLen = decimalNum.length
for (let i = 0; i < decLen; i++) {
let n = decimalNum.substr(i, 1)
if (n !== '0') {
chineseStr += cnNums[Number(n)] + cnDecUnits[i]
}
}
}
if (chineseStr === '') {
chineseStr += cnNums[0] + cnIntLast + cnInteger
} else if (decimalNum === '') {
chineseStr += cnInteger
}
return chineseStr
}
- 1.15 分级高效递归汇总,支持数组,单条数据的汇总
let utils = {
performGradedSummarySingData(obj, gradedCalcFields) { // 分级汇总单条数据计算
let self = this
if (Array.isArray(obj.children) && obj.children.length) {
gradedCalcFields.forEach((key) => {
obj[key] = obj.children.reduce((preResult, next) => {
let curItemGradedSummaryValue = 0
if (Array.isArray(next.children) && next.children.length) {
curItemGradedSummaryValue = parseFloat(self.performGradedSummarySingData(next, gradedCalcFields)[key])
} else {
curItemGradedSummaryValue = parseFloat(next[key])
}
return preResult + (isNaN(curItemGradedSummaryValue) ? 0 : curItemGradedSummaryValue)
}, 0)
})
}
return obj
},
performGradedSummaryData(data, gradedCalcFields) { // 数组分级汇总计算
let self = this
data.forEach((item) => {
self.performGradedSummarySingData(item, gradedCalcFields)
})
return data
},
listToTreeByNestCodeLength(data, nestCodeKey, ) { // 平行数据 根据nestCodeKey 长度 生成嵌套数据
let map = {} // 构建map
data.forEach(function (item) {
map[item[nestCodeKey]] = item
item.children = []
})
let treeData = []
data.forEach(item => {
let pnestCodeKey = item[nestCodeKey]
pnestCodeKey = pnestCodeKey.slice(0, pnestCodeKey.length - 1)
let mapItem = map[item[pnestCodeKey]]
while (!mapItem && pnestCodeKey !== '') {
pnestCodeKey = pnestCodeKey.slice(0, pnestCodeKey.length - 1)
mapItem = map[pnestCodeKey]
}
if (mapItem) {
(mapItem.children || (mapItem.children = [])).push(item)
} else {
treeData.push(item)
}
})
return treeData
}
}
设计一个方法将
let list = [
{
a: 0,
b: 0,
itemCode: 10
},
{
a: 0,
b: 0,
itemCode: 101001
},
{
a: 1,
b: 3,
itemCode: 1010010001
},
{
a: 2,
b: 3,
itemCode: 1010010002
},
{
a: 3,
b: 7,
itemCode: 101002
},
{
a: 2,
b: 2,
itemCode: 11
}
]
转换得到:
let list2 = [
{
a: 6,
b: 13,
itemCode: 10,
children: [
{
a: 3,
b: 6,
itemCode: 101001,
children: [
{
a: 1,
b: 3,
itemCode: 1010010001
},
{
a: 2,
b: 3,
itemCode: 1010010002
}
]
},
{
a: 3,
b: 7,
itemCode: 101002
}
]
},
{
a: 2,
b: 2,
itemCode: 11
}
]
let gradedCalcFields = ['a', 'b']
utils.performGradedSummaryData(utils.listToTreeByNestCodeLength(list,'itemcode'), gradedCalcFields)
- 1.16 Excel 处理相关函数
let excelUtils = {
columnLabelToIndex(label) { // 获取列字母索引转化为数字索引
if (!/[A-Z]+/.test(label.toLocaleUpperCase())) {
throw new Error('Invalid parameter,Expect a String<Alphabetic>!')
}
let index = 0
let chars = label.toLocaleUpperCase().split('')
for (let i = 0; i < chars.length; i++) {
index += (chars[i].charCodeAt() - 'A'.charCodeAt() + 1) * Math.pow(26, chars.length - i - 1)
}
return index - 1
}
getExcelColumnLabel(num) { // 获取索引获取列字母
// 方法一
if (!/[0-9]+/.test(num)) {
throw new Error('Invalid parameter,Expect a Number!')
}
let ordA = 'A'.charCodeAt(0)
let ordZ = 'Z'.charCodeAt(0)
let len = ordZ - ordA + 1
let result = ''
while (num >= 0) {
result = String.fromCharCode(num % len + ordA) + result
num = Math.floor(num / len) - 1
}
return result
// 方法二
/*
let temp = ''
let i = Math.floor(Math.log(25.0 * (num) / 26.0 + 1) / Math.log(26)) + 1
if (i > 1) {
let sub = num - 26 * (Math.pow(26, i - 1) - 1) / 25
for (let j = i; j > 0; j--) {
temp = temp + String.fromCharCode(sub / Math.pow(26, j - 1) + 65)
sub = sub % Math.pow(26, j - 1)
}
} else {
temp = temp + String.fromCharCode(num + 65)
}
return temp
*/
}
}
2. 处理技巧
- 2.1运用存储加速递归
var fibonacci = function (n) {
return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}
var fibonacci = (function () {
var cache = [0, 1]
return function (n) {
if (cache[n] === undefined) {
for (var i = cache.length; i <= n; ++i) {
cache[i] = cache[i - 1] + cache[i - 2]
}
}
return cache[n];
}
})()
- 2.2高阶函数
// 高阶函数, 它接收一个方法作为参数, 返回一个该方法运用存储后的新方法。
var memoize = function (func) {
var cache = {};
return function () {
var key = Array.prototype.slice.call(arguments).toString();
return key in cache ? cache[key] : (cache[key] = func.apply(this, arguments));
}
}
// ES6版本的memoize函数如下:
var memoizeES6 = function (func) {
const cache = {};
return (...args) => {
const key = [...args].toString()
return key in cache ? cache[key] : (cache[key] = func(...args));
}
}
fibonacci = memoizeES6(fibonacci);
// GCD(最大公约数)
var gcd = memoize(
function (a, b) {
var t;
if (a < b)
t = b, b = a, a = t;
while (b != 0)
t = b, b = a % b, a = t;
return a;
})
gcd(27, 183)
var factorial = memoize(
function (n) {
return (n <= 1) ? 1 : n * factorial(n - 1);
})
factorial(5); //=> 120
- 2.3Math.pow实现
var myPow = function (x, n) {
// !本题核心: 当n为奇数和偶数时两种情况的讨论
// 情况1: (2,4) = (2,2) * (2,2)
// 情况2:(2,5) = (2,2) * (2,2) * 2
// 首先n是有可能为0,正,负数的
if (n === 0) return 1;
// 无论正负数我们都先将其转换为正数计算
const res = dfs(x, Math.abs(n));
if (n > 0) {
return res;
} else {
return 1 / res;
}
function dfs(x, n) {
// 递归的结束条件
if (n === 1) {
return x;
}
let temp = dfs(x, Math.floor(n / 2));
return n % 2 ? (x * temp * temp) : (temp * temp)
}
}
- 2.4判断两个json数据单纯的数据数值相等
递归,精确数据类型获取比较,闭环等
let CompareUtil = {
getType(obj) {
return Object.prototype.toString.call(obj).slice(8, -1)
},
compareObj(obj1, obj2) {
if (typeof (obj1) === 'object' && typeof (obj2) === 'object') {
return this.compareJson(obj1, obj2)
}
else {
console.log("传入数据类型不是JSON")
}
},
compareJson(obj1, obj2) {
try {
if (this.getType(obj1) !== this.getType(obj2)) {
return false
}
else if (this.getType(obj1) === 'Array') {
return this.comArrayJson(obj1, obj2)
}
else if (this.getType(obj1) === 'Object') {
return this.comObjectJson(obj1, obj2)
}
else if (this.getType(obj1) === "String") {
return obj1 === obj2
}
else if (this.getType(obj1) === "Number") {
return obj1 === obj2
}
else if (this.getType(obj1) === "Null") {
return null === obj2
}
else if (this.getType(obj1) === "Function") {
return obj1 + '' === obj2 + ''
}
else {
return false
}
} catch (e) {
return false
}
},
comArrayJson(arr1, arr2) {
let self = this
if (arr1.length === arr2.length) {
return arr1.every((item, index) => {
return self.compareJson(item, arr2[index])
})
}
else {
return false
}
},
comObjectJson(obj1, obj2) {
let self = this
if (Object.keys(obj1).join("") === Object.keys(obj2).join("")) {
return Object.keys(obj1).every((item, index) => {
return self.compareJson(obj1[item], obj2[item])
})
} else {
return false
}
}
}
调用示例,引入闭环
console.log(CompareUtil.compareObj({}, {}))
let b = { a: 1 }
b.a = b
let a = { b: 1 }
a.b = a
console.log(CompareUtil.compareObj(a, b))
- 2.5同步异步
请用程序表达王老板与[媳妇,小三,秘书]的旅途[[吃饭,睡觉,打豆豆],[吃饭,买电影票,看电影],[吃饭,散步,玩游戏]]生涯。注意:王老板同一时刻只能选一个人干一件事,过程需要花费一定的时间。
const sleep = (time) => new Promise((resolve) => void setTimeout(resolve, time)); // 模拟延迟
class HappyEvent {
constructor(name, steps) {
this.name = name;
this.steps = steps;
}
async do(peoples) {
const { steps } = this;
const { length } = peoples;
const peoplesStr = `${peoples.slice(0, length - 1).join("、")}和${peoples[length - 1]
}`;
HappyEvent.log(`${peoplesStr}准备去${this.name}`);
for (let i = 0; i < steps.length; i++) {
const step = steps[i];
HappyEvent.log(`${peoplesStr}在${step.name}...`);
await sleep(step.time * 1000); // 模拟延迟
// await new Promise((reject) => {
// setTimeout(() => {
// reject();
// }, step.time * 1000);
// });
}
}
static log(info) {
const date = new Date();
console.log(`${date.getSeconds()}分
${info}`);
}
}
class Happy {
constructor(man, girls) {
Object.assign(this, { man, girls });
}
async play(events) {
HappyEvent.log("旅途开始!");
const { man, girls } = this;
for (let i = 0; i < girls.length; i++) {
const girl = girls[i];
const event = events[Math.floor(Math.random() * events.length)];
// console.log(event);
await event.do([man, girl]);
}
HappyEvent.log("旅途结束!");
}
}
new Happy("张经理", ["张夫人", "李秘书", "小三"]).play([
new HappyEvent("散步", [
{
name: "找饭店",
time: 1,
},
{
name: "吃饭",
time: 5,
},
{
name: "散步",
time: 10,
}]),
new HappyEvent("打豆豆", [
{
name: "吃饭",
time: 3,
},
{
name: "睡觉",
time: 1,
},
{
name: "打豆豆",
time: 8,
}]),
new HappyEvent("看电影", [
{
name: "找电影院",
time: 3,
},
{
name: "买电影票",
time: 1,
},
{
name: "看电影",
time: 8,
}]),
new HappyEvent("玩游戏", [
{
name: "找酒店",
time: 1,
},
{
name: "开房",
time: 1,
},
{
name: "打豆豆",
time: 10,
}])
]);
- 2.6洋葱模型
class onionModel {
// 洋葱模型
middleware = [];
constructor(obj) {
this.ctx = obj || {};
}
use(fn) {
this.middleware.push(fn);
}
start() {
let fn = this.compose(this.middleware);
return fn(this.ctx).then(this.respond);
}
respond() {
console.log(`响应数据`);
}
dispatch(index, ctx) {
let fn = this.middleware[index];
if (!fn) return Promise.resolve();
return fn(ctx, () => this.dispatch(index + 1, ctx));
}
compose(middleware) {
let self = this;
return function (ctx) {
return self.dispatch(0, ctx);
};
}
// compose(middleware) {
// return function (ctx) {
// return dispatch(0);
// function dispatch(index) {
// let fn = middleware[index];
// if (!fn) return Promise.resolve();
// return fn(ctx, () => dispatch(index + 1))
// }
// }
// }
}
/*
const sleep=time=>new Promise((resolve,reject)=>{setTimeout(()=>{resolve()},time)})
let onionModelCall = new onionModel()
onionModelCall.use(async (ctx, next) => {
console.log(ctx)
console.log(`第一层 start`)
await sleep(1000)
await next()
await sleep(1000)
console.log(`第一层 end`)
})
onionModelCall.use(async (ctx, next) => {
console.log(`第二层 start`)
await sleep(2000)
await next()
await sleep(2000)
console.log(`第二层 end`)
})
onionModelCall.use(async (ctx, next) => {
console.log(`第三层 start`)
await sleep(3000)
await next()
await sleep(3000)
console.log(`第三层 end`)
})
//执行监听回调,模拟接受请求后的处理
onionModelCall.start()
*/