一、手动实现同步钩子函数

1、SyncHook

class SyncHook {
// 钩子是同步的
constructor(args){
this.tasks = [];
}
tap(name,task){
this.tasks.push(task)
}
call(...args){
this.tasks.forEach(
(task)=>task(...args)
)
}
} // 绑定事件就是订阅
let hook = new SyncHook(['name']); hook.tap('react',function (name) {
console.log('react',name)
});
hook.tap('node',function (name) {
console.log('node',name)
}); hook.call('dellyoung');

2、SyncWaterfallHook

class SyncWaterfallHook {
// 钩子是同步的
constructor(args){
this.tasks = [];
}
tap(name,task){
this.tasks.push(task)
}
call(...args){
let [first,...others] = this.tasks;
let ret = first(...args);
others.reduce(
(a,b)=>{
// a 上一个 b 下一个
return b(a);
},ret
)
}
} // 绑定事件就是订阅
let hook = new SyncWaterfallHook(['name']); hook.tap('react',function (name) {
console.log('react1',name);
return 'reactOk'
}); hook.tap('node',function (name) {
console.log('node2',name);
return 'nodeOk'
}); hook.tap('webpack',function (name) {
console.log('webpack',name)
}); hook.call('dellyoung');

3、SyncLoopHook

class SyncLoopHook {
// 钩子是同步的
// 只要返回不是undefined就会一直循环
constructor(args){
this.tasks = [];
}
tap(name,task){
this.tasks.push(task)
}
call(...args){
this.tasks.forEach(
task=>{
let ret;
do {
ret = task(...args)
}while (ret !== undefined)
}
)
}
} // 绑定事件就是订阅
let hook = new SyncLoopHook(['name']);
let total = 0; hook.tap('react',function (name) {
console.log('react',name);
return ++total === 3?undefined:'继续学'
}); hook.tap('node',function (name) {
console.log('node',name);
}); hook.tap('webpack',function (name) {
console.log('webpack',name)
}); hook.call('dellyoung');

4、SyncBailHook

class SyncBailHook {
// 钩子是同步的
constructor(args){
this.tasks = [];
}
tap(name,task){
this.tasks.push(task)
}
call(...args){
let ret; // 当前函数返回值
let index=0; // 先执行第一个
do{
ret = this.tasks[index++](...args)
}while (ret === undefined && index < this.tasks.length);
}
} // 绑定事件就是订阅
let hook = new SyncBailHook(['name']); hook.tap('react',function (name) {
console.log('react1',name);
// return '停止'
});
hook.tap('node',function (name) {
console.log('node2',name)
}); hook.call('dellyoung');

  

二、手动实现异步钩子函数

1、AsyncParallelBailHook

类似promise.all[]

class AsyncParallelBailHook {
// 钩子是同步的
// 只要返回不是undefined就会一直循环
constructor(args){
this.tasks = [];
}
tapAsync(name,task){
this.tasks.push(task)
}
callAsync(...args){
let finalCallBack = args.pop(); // 拿出最终的函数
let index = 0;
let done = () => {
index++;
if(index === this.tasks.length){
finalCallBack();
}
};
this.tasks.forEach(task=>{
task(...args,done)
})
}
} // 绑定事件就是订阅
let hook = new AsyncParallelBailHook(['name']); hook.tapAsync('react',function (name,callback) {
setTimeout(()=>{
console.log('react',name);
callback();
},5000
);
}); hook.tapAsync('node',function (name,callback) {
setTimeout(()=>{
console.log('node',name);
callback();
},1000
);
}); hook.callAsync('dellyoung',function () {
console.log('newBegin')
});

promise版本的AsyncParallelBailHook

class AsyncParallelBailHook {
// 钩子是同步的
// 只要返回不是undefined就会一直循环
constructor(args) {
this.tasks = [];
} tabPromise(name, task) {
this.tasks.push(task)
} promise(...args) {
let tasks = this.tasks.map(
(task) => {
return task(...args)
}
);
// let tasks = this.tasks.map(task => task(...args));
return Promise.all(tasks);
}
} // 绑定事件就是订阅
let hook = new AsyncParallelBailHook(['name']); hook.tabPromise('react', function (name) {
return new Promise(
(resolve, reject) => {
setTimeout(() => {
console.log('react', name);
resolve();
}, 1000
);
}
)
}); hook.tabPromise('node', function (name) {
return new Promise(
(resolve, reject) => {
setTimeout(() => {
console.log('node', name);
resolve();
}, 2000
);
}
)
}); hook.promise('dellyoung').then(function () {
console.log('newBegin')
});

2、AsyncSeriesHook

异步串行

class AsyncSeriesHook {
constructor(args) {
this.tasks = [];
} tabAsync(name, task) {
this.tasks.push(task)
} callAsync(...args) {
let finalCallBack = args.pop();
let index = 0;
let next = () => {
if(this.tasks.length === index){
return finalCallBack();
}
let task = this.tasks[index++];
task(...args, next);
};
next();
}
} // 绑定事件就是订阅
let hook = new AsyncSeriesHook(['name']); hook.tabAsync('react', function (name, callback) {
setTimeout(() => {
console.log('react', name);
callback();
}, 3000
);
}); hook.tabAsync('node', function (name, callback) {
setTimeout(() => {
console.log('node', name);
callback();
}, 1000
)
}); hook.callAsync('dellyoung',function () {
console.log('newBegin')
});

promise版本的AsyncSeriesHook 

class AsyncSeriesHook {
constructor(args) {
this.tasks = [];
} tabPromise(name, task) {
this.tasks.push(task)
} promise(...args) {
// 类redux源码
let [first,...other] = this.tasks;
return other.reduce(
(prom,n)=>{
return prom.then(()=>n(...args))
},first(...args)
)
}
} // 绑定事件就是订阅
let hook = new AsyncSeriesHook(['name']); hook.tabPromise('react', function (name) {
return new Promise(
(resolve, reject) => {
setTimeout(() => {
console.log('react', name);
resolve();
}, 1000
);
}
)
}); hook.tabPromise('node', function (name) {
return new Promise(
(resolve, reject) => {
setTimeout(() => {
console.log('node', name);
resolve();
}, 1000
);
}
)
}); hook.promise('dellyoung').then(function () {
console.log('newBegin')
});

  

3、AsyncSeriesWaterfallHook

异步瀑布串行

class AsyncSeriesWaterfallHook {
constructor(args) {
this.tasks = [];
} tapAsync(name, task) {
this.tasks.push(task)
} callAsync(...args) {
let finalCb = args.pop();
let index = 0;
let next = (err,data) => {
let task = this.tasks[index];
if(!task) return finalCb();
if(err) return ;
if(index===0){
// 执行第一个
task(...args,next)
}else {
task(data,next)
}
index++;
};
next()
}
} // 绑定事件就是订阅
let hook = new AsyncSeriesWaterfallHook(['name']); hook.tapAsync('react', function (name, cb) {
setTimeout(() => {
console.log('react', name);
cb(null, 'result1');
}, 1000
);
}); hook.tapAsync('node', function (data, cb) {
setTimeout(() => {
console.log('node', data);
cb(null);
}, 2000
);
}); hook.callAsync('dellyoung',function () {
console.log('newBegin')
});

  

[webpack]深入学习webpack核心模块tapable的更多相关文章

  1. Webpack 核心模块 tapable 解析(转)

        原文出自:https://www.pandashen.com 前言 Webpack 是一个现代 JavaScript 应用程序的静态模块打包器,是对前端项目实现自动化和优化必不可少的工具,We ...

  2. webpack核心模块tapable用法解析

    前不久写了一篇webpack基本原理和AST用法的文章,本来想接着写webpack plugin的原理的,但是发现webpack plugin高度依赖tapable这个库,不清楚tapable而直接去 ...

  3. webpack核心模块tapable源码解析

    上一篇文章我写了tapable的基本用法,我们知道他是一个增强版版的发布订阅模式,本文想来学习下他的源码.tapable的源码我读了一下,发现他的抽象程度比较高,直接扎进去反而会让人云里雾里的,所以本 ...

  4. webpack4核心模块tapable源码解析

    _ 阅读目录 一:理解Sync类型的钩子 1. SyncHook.js 2. SyncBailHook.js 3. SyncWaterfallHook.js 4. SyncLoopHook.js 二: ...

  5. 深入学习webpack(一)

    深入学习webpack(一) 模块化的相关库和工具已经很多了,包括require.js.sea.js和一些工程化工具webpack.gulp.grant.那么我们该如何选择呢? 其实,我们只需要掌握了 ...

  6. 深入学习webpack(二)

    深入学习webpack(二) 在深入学习webpack(一)中,我通过一个例子介绍了webpack的基本使用方法,下面将更为系统的学习webpack的基本概念,对于一门技术的掌握我认为系统化还是很重要 ...

  7. webpack入门学习手记(一)

    本人微信公众号:前端修炼之路,欢迎关注. 之前用过gulp.grunt,但是一直没有学习过webpack.这两天刚好有时间,学习了下webpack.webpack要想深入研究,配置的东西比较多,网上的 ...

  8. WebPack 简明学习教程

    WebPack 简明学习教程 字数1291 阅读22812 评论11 喜欢35 WebPack是什么 一个打包工具 一个模块加载工具 各种资源都可以当成模块来处理 网站 http://webpack. ...

  9. webpack的学习

    什么是webpack? 他有什么优点? 首先对于很多刚接触webpack人来说,肯定会问webpack是什么?它有什么优点?我们为什么要使用它?带着这些问题,我们来总结下如下: Webpack是前端一 ...

随机推荐

  1. C++——new & delete

    C++ new Complex类 String类 C++ delete Comlex类 String类 array new 一定要搭配array delete VC架构下new内存分配演绎 Linux ...

  2. MySQL分布式数据库架构:分库、分表、排序、分页、分组、实现教程

    MySQL分库分表总结: 单库单表 : 单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到. 单库多表 : 随着用户数量的增加, ...

  3. 开源框架---tensorflow c++ API中./configure步骤细节

    u@u160406:~/tf1.13/tensorflow$ git checkout r1.13 分支 r1.13 设置为跟踪来自 origin 的远程分支 r1.13.切换到一个新分支 'r1.1 ...

  4. VS Code Monokai Pro验证

    最新的VS Code Monokai Pro激活方式 需要vscode,并且安装了monokai pro插件 进入目录 Mac OS cd -/.vscode/extensions/monokai.t ...

  5. 12 复习 - webpack基本配置1

    1.npm包管理工具 npm init -y 如果创建的项目的根目录名称是中文或者包含中文,不能使用-y npm init 回车时要求你输入包的名称,自己手写项目名称,例test 2.新建src,di ...

  6. Mybatis面向接口式编程

    Mybatis面向接口编程 1.xml文件书写格式 <?xml version="1.0" encoding="UTF-8" ?> <!DOC ...

  7. CentOS环境部署(Nginx+Mariadb+Java+Tomcat)

    1.安装nginx 安装 yum install nginx 启动 yum install nginx 开机自启 sudo systemctl enable nginx 2.安装mariadb 安装 ...

  8. vue2 单一事件中心管理组件通信

  9. ModbusRTU模式和结束符(转)

    Modbus RTU模式的协议字段 起始位 设备地址 功能码 数据 CRC校验 结束符 至少3.5个字符 8bit 8bit N*8bit 16bit 至少3.5个字符 Modbus协议RTU模式要求 ...

  10. SQL server 中rowcount与@@rowcount 的使用

    rowcount的用法: rowcount的作用就是用来限定后面的sql在返回指定的行数之后便停止处理,比如下面的示例,set rowcount 10select * from 表A 这样的查询只会返 ...