Tapable
Webpack is essentially an event flow mechanism. Its workflow is to connect plug-ins in series. The core of Webpack is Tapable, which is a bit like the event library of nodejs, and mainly depends on the publisher-subscriber mode.
The difference between hook function and callback function
Hook function: executes at the first time of capturing a message.
Callback function: At the end of capture, it is finally executed
SyncHook
- 1.start.js let { SyncHook } = require('tapable') class Lession { constructor() { this.hook = { arch: new SyncHook(['name']) } } tap() { //Registered listener function this.hook.arch.tap('lheng', (name) => { console.log('node', name); }) this.hook.arch.tap('wting', (name) => { console.log('wting', name); }) } //When tap is used, two listening events are added to the array start() { this.hook.arch.call('lheng') } } let l = new Lession() l.tap() //Register these two events l.start() //Start hook
Implementing SyncHook
class SyncHook { //Synchronized hook constructor(args) { //args => ['name] this.tasks = [] } call(...args) { this.tasks.forEach((task) => task(...args)) } tap(name, task) { this.tasks.push(task) } } let hook = new SyncHook(['name']) hook.tap('react', function(name) { console.log('react', name); }) hook.tap('java', function(name) { console.log('java', name); }) hook.call('lheng')
SyncBailHook
Synchronized insurance hook, where execution is terminated if the return value of a function in the middle is not undefined
let { SyncBailHook } = require('tapable') class Lession { constructor() { this.hook = { arch: new SyncBailHook(['name']) } } tap() { //Registered listener function this.hook.arch.tap('lheng', (name) => { console.log('node', name); return 'stop' }) this.hook.arch.tap('wting', (name) => { console.log('wting', name); }) } //When tap is used, two listening events are added to the array start() { this.hook.arch.call('lheng') } } let l = new Lession() l.tap() //Register these two events l.start() //Start hook
Implementing SyncBail Hook
class SyncBailHook { //Synchronized hook constructor(args) { //args => ['name] this.tasks = [] } call(...args) { let res, index = 0; do { res = this.tasks[index++](...args) } while (res === undefined && index < this.tasks.length) } tap(name, task) { this.tasks.push(task) } } let hook = new SyncBailHook(['name']) hook.tap('react', function(name) { console.log('react', name); // return 'stop' }) hook.tap('java', function(name) { console.log('java', name); }) hook.call('lheng')
SyncWaterfallHook
Waterfall flow, the result of intermediate execution will be passed on to the next
let { SyncWaterfallHook } = require('tapable') class Lession { constructor() { this.hook = { arch: new SyncWaterfallHook(['name']) } } tap() { //Registered listener function this.hook.arch.tap('lheng', (name) => { console.log('node', name); return 'waterFail' }) this.hook.arch.tap('wting', (data, name) => { console.log('wting', data, name); }) } //When tap is used, two listening events are added to the array start() { this.hook.arch.call('lheng') } } let l = new Lession() l.tap() //Register these two events l.start() //Start hook
Result:
Reduc function introduction:
The reduce() method receives a function as an accumulator, and reduces each element in the array to perform a callback function in turn. It does not include elements deleted or never assigned in the array. It accepts four parameters: initial value (the return value of the previous callback), current element value, current index, and original array.
arr.reduce(callback,[initialValue]) callback:The function contains four parameters - previousValue (The value returned by the last call callback, or the initial value provided( initialValue)) - currentValue (Currently processed elements in an array) - index (Index of the current element in the array) - array (Array of calls) initialValue (As the first call callback The first parameter.)
Implementing SyncWaterfall hook
class SyncWaterfallHook { //Synchronized hook constructor(args) { //args => ['name] this.tasks = [] } call(...args) { let [first, ...other] = this.tasks let res = first(...args) other.reduce((a, b) => { b(a) }, res) } tap(name, task) { this.tasks.push(task) } } let hook = new SyncWaterfallHook(['name']) let index = 0 hook.tap('react', function(name) { console.log('react', name); // Return + index = 3?Undefined:'Continue learning' return 'stop' }) hook.tap('java', function(name) { console.log('java', name); }) hook.call('lheng')
SyncLoopHook
The loop executes an event until it returns undefined
let { SyncLoopHook } = require('tapable') class Lession { constructor() { this.hook = { arch: new SyncLoopHook(['name']) } } tap() { //Registered listener function let index = 0 this.hook.arch.tap('lheng', (name) => { console.log('node', name); return ++index == 3 ? undefined : 'Continue learning' // return 'waterFail' }) this.hook.arch.tap('wting', (name) => { console.log('wting', name); }) } //When tap is used, two listening events are added to the array start() { this.hook.arch.call('lheng') } } let l = new Lession() l.tap() //Register these two events l.start() //Start hook
Implementing SyncLoophook
class SyncLoopHook { //Synchronized hook constructor(args) { //args => ['name] this.tasks = [] } call(...args) { let res this.tasks.forEach((task) => { do { res = task(...args) } while (res != undefined) }) } tap(name, task) { this.tasks.push(task) } } let hook = new SyncLoopHook(['name']) let index = 0 hook.tap('react', function(name) { console.log('react', name); return ++index == 3 ? undefined : 'Continue learning' // return 'stop' }) hook.tap('java', function(name) { console.log('java', name); }) hook.call('lheng')
AsyncParallelHook
let { AsyncParallelHook } = require('tapable') //Async Parallel Hook Asynchronous Parallel Hook Hook // Parallel, sending multiple requests at the same time. After the request has been sent, a callback is executed. // Asynchronous hooks (serial, parallel) // Registration method tap registration, tapAsync registration class Lession { constructor() { this.hook = { arch: new AsyncParallelHook(['name']) } } tap() { //Registered listener function let index = 0 this.hook.arch.tapAsync('lheng', (name, cb) => { setTimeout(() => { console.log('lheng', name); cb() // Identify that the callback function has been executed, and only when all CBS have been executed will the final callback function be invoked }, 1000); }) this.hook.arch.tapAsync('node', (name, cb) => { setTimeout(() => { console.log('node', name); // cb() }, 1000); }) } //When tap is used, two listening events are added to the array start() { this.hook.arch.callAsync('lheng', () => { console.log('end'); }) } } let l = new Lession() console.log(l); l.tap() //Register these two events l.start() //Start hook
Implementation of Async Parallel Hookfun1
class AsyncParallelHook { //Synchronized hook constructor(args) { //args => ['name] this.tasks = [] } callAsync(...args) { let index = 0; let finalCB = args.pop() //Take out the final function. let done = () => { //Promise.all index++ if (index == this.tasks.length) { finalCB() } } this.tasks.forEach(task => { task(...args, done) }) } tapAsync(name, task) { this.tasks.push(task) } } let hook = new AsyncParallelHook(['name']) let index = 0 hook.tapAsync('react', function(name, cb) { setTimeout(() => { console.log('react', name); cb() }, 1000); // Return + index = 3?Undefined:'Continue learning' }) hook.tapAsync('java', function(name, cb) { setTimeout(() => { console.log('java', name); cb() }, 1000); }) hook.callAsync('lheng', () => { console.log('end'); })
The difference between map and forEach
The forEach() method does not return the execution result, but undefined. That is, forEach() modifies the original array. The map() method gets a new array and returns it. Next we'll go to all Promise return values, using map naturally
Implementation of Async Parallel Hookfun2-promise
// TapAsync (cb) tapPromise is registered synchronously with tapAsync (cb) tapPromise (registration is promise) // Three methods of calling call Async promise class AsyncParallelHook { //Synchronized hook constructor(args) { //args => ['name] this.tasks = [] } promise(...args) { let tasks = this.tasks.map(task => { task(...args) }) return Promise.all(tasks) } tapPromise(name, task) { this.tasks.push(task) } } let hook = new AsyncParallelHook(['name']) let index = 0 hook.tapPromise('react', function(name) { return new Promise((resolve, reject) => { setTimeout(() => { console.log('react', name); resolve() }, 1000); }) }) hook.tapPromise('java', function(name) { return new Promise((resolve, reject) => { setTimeout(() => { console.log('java', name); resolve() }, 1000); }) }) hook.promise('lheng') .then( function() { console.log('end'); } )