предисловие
Зачем нам нужно изучать tapable, потому что... исходный код webpack использует tapable для реализации монтирования хуков. Как код, который немного преследуется, как webpack может довольствоваться только его использованием? Конечно, мы должны искать в исходниках и пишем Loader,plugin.До этого,если не знаешь как пользоваться tapable,то исходник читать не надо,ничего не поймешь...Итак,поговорим о tapable сегодня.
1. tapable
Webpack — это, по сути, механизм потока событий.Его рабочий процесс заключается в последовательном подключении различных плагинов, и ядром всего этого является Tapable.Основной компилятор в webpack и компиляция, отвечающие за создание пакетов, Tapable.
Параметры, передаваемые при создании экземпляра tapable, не влияют на работу программы, а только помогают читателям исходного кода.
Точно так же при использовании tap* для регистрации слушателя первый переданный параметр является просто идентификатором и не будет иметь никакого влияния на выполнение программы. Второй параметр — функция обратного вызова.
2. Использование Tapable
const {
SyncHook,
SyncBailHook,
SyncWaterHook,
SyncLoopHook
AsyncParallelHook,
AsyncParallelBailHook,
AsyncSeriesHook,
AsyncSeriesBailHook,
AsyncSeriesWaterfallHook
} = require("tapable");
серийный номер | имя хука | способ исполнения | Использовать баллы |
---|---|---|---|
1 | SyncHook | Синхронный последовательный | Не заботьтесь о возвращаемом значении функции слушателя |
2 | SyncBailHook | Синхронный последовательный | Пока возвращаемая стоимость одного из функций слушателя не является NULL, остальная логика пропускается |
3 | SyncWaterfallHook | Синхронный последовательный | Возвращаемое значение предыдущей функции прослушивателя будет передано в качестве параметра следующей функции прослушивателя. |
4 | SyncLoopHook | Синхронный последовательный | Когда функция прослушивателя срабатывает, если функция прослушивателя возвращает true, функция прослушивателя будет выполняться повторно, а если она возвращает значение undefined, это означает выход из цикла. |
5 | AsyncParallelHook | асинхронный параллелизм | Не заботьтесь о возвращаемом значении функции слушателя |
6 | AsyncParallelBailHook | асинхронный параллелизм | Пока возвращаемое значение функции прослушивателя не равно нулю, выполнение следующей функции прослушивателя будет игнорироваться, и она перейдет непосредственно к функции обратного вызова, которая запускает привязку функции, например callAsync, а затем выполнит связанную функцию обратного вызова. . |
7 | AsyncSeriesHook | Асинхронный последовательный | Не заботьтесь о параметрах callback() |
8 | AsyncSeriesBailHook | Асинхронный последовательный | Если параметр callback() не равен нулю, функция обратного вызова, которая запускает привязку функции, например callAsync, будет выполняться напрямую. |
9 | AsyncSeriesWaterfallHook | Асинхронный последовательный | Второй параметр обратного вызова (ошибка, данные) в предыдущей функции мониторинга может использоваться как параметр следующей функции мониторинга. |
3. Хуки типа Sync*
- Порядок выполнения плагинов, зарегистрированных под этим хуком, последовательный.
- Вы можете использовать только регистрацию касания, а не регистрацию tapPromise и tapAsync.
3.1 SyncHook
Последовательное синхронное выполнение, не заботьтесь о возвращаемом значении После того, как касания зарегистрированы в экземпляре SyncHook, пока экземпляр вызывает метод вызова, функции обратного вызова этих касаний будут выполняться последовательно.
let queue = new SyncHook(['没任何作用的参数']);
queue.tap(1,(name,age)=>{
console.log(name,age)
})
queue.tap(2,(name,age)=>{
console.log(name,age)
})
queue.tap(3,(name,age)=>{
console.log(name,age)
})
queue.call('bearbao',8)
// 输出结果
// 'bearbao' 8
// 'bearbao' 8
// 'bearbao' 8
3.1.1 Реализация SyncHook
class SyncHook {
constructor(){
this.listeners = [];
}
tap(formal,listener){
this.listeners.push(listener)
}
call(...args){
this.listeners.forEach(l=>l(...args))
}
}
3.2 SyncBailHook
Последовательное синхронное выполнение, если возвращаемое значение не равно нулю, остальная часть логики пропускается.
let queue = new SyncBailHook(['name'])
queue.tap(1,name=>{
console.log(name)
})
queue.tap(1,name=>{
console.log(name)
return '1'
})
queue.tap(1,name=>{
console.log(name)
})
queue.call('bearbao')
// 输出结果,只执行前面两个回调,第三个不执行
// bearbao
// bearbao
выполнить
class SyncBailHook {
constructor(){
this.listeners = [];
}
tap(formal,listener){
this.listeners.push(listener)
}
call(...args){
for(let i=0;i<this.listeners.length;i++){
if(this.listeners[i]()) break;
}
}
}
3.3 SyncWaterHook
Последовательное синхронное выполнение, первая зарегистрированная функция обратного вызова получит все параметры, переданные вызовом, а каждая последующая функция обратного вызова получит только один параметр, который является возвращаемым значением предыдущей функции обратного вызова.
let queue = new SyncWaterHook(['name','age']);
queue.tap(1,(name,age)=>{
console.log(name,age)
return 1
})
queue.tap(2,(ret)=>{
console.log(ret)
return 2
})
queue.tap(3,(ret)=>{
console.log(ret)
return 3
})
queue.call('bearbao', 3)
// 输出结果
// bearbao 3
// 1
// 2
Реализация SyncWaterHook Метод SyncWaterHook очень похож на метод compose в redux, который передает возвращаемое значение одной функции в качестве параметра следующей функции.
Если у вас есть сомнения по поводу реализованного ниже метода call, студенты, которые плохо понимают, могут перейти к моей предыдущей интерпретации функции compose, которая имеет подробное введение, поэтому я не буду здесь вдаваться в подробности.
Реализация и анализ расширенного метода компоновки Redux
class SyncWaterHook{
constructor(){
this.listeners = [];
}
tap(formal,listener){
this.listener.unshift(listener);
}
call(...args){
this.listeners.reduce((a,b)=>(...args)=>a(b(...args)))(...args)
}
}
3.4 SyncLoopHook
последовательное синхронное исполнение, Функция слушателя возвращает значение true, чтобы продолжить цикл, и возвращает значение undefined, чтобы завершить цикл.
let queue = new SyncLoopHook;
let index = 0;
queue.tap(1,_=>{
index++
if(index<3){
console.log(index);
return true
}
})
queue.call();
// 输出结果
// 1
// 2
Реализация SyncLoopHook
class SyncLoopHook{
constructor() {
this.tasks=[];
}
tap(name,task) {
this.tasks.push(task);
}
call(...args) {
this.tasks.forEach(task => {
let ret=true;
do {
ret = task(...args);
}while(ret)
});
}
}
4. Хуки асинхронного* типа
- Поддержка tap, tapPromise, tapAsync регистрация
- Каждый раз, когда вы вызываете TAP, Tapsync, TapPromise зарегистрированы различные типы подключаемых крючков, вызовов Callasync, режим обещания. Фактически, чтобы выполнить определенную политику реализации, вызовите метод Compile, чтобы быстро составить метод для выполнения этих плагинов.
4.1 AsyncParallel
Асинхронное параллельное выполнение
4.1.1 AsyncParallelHook
Не заботьтесь о возвращаемом значении функции слушателя.
Существует три режима регистрации/выпуска, а именно:
Асинхронная подписка | метод вызова |
---|---|
tap | callAsync |
tapAsync | callAsync |
tapPromise | promise |
- использовать по крану
Параметры триггерной функции, последний параметр — это обратный вызов после завершения выполнения функции обратного вызова асинхронного мониторинга, а остальные параметры — это параметры, передаваемые в функцию обратного вызова.
let queue = new AsyncParallelHook(['name']);
console.time('cost');
queue.tap('1',function(name){
console.log(name,1);
});
queue.tap('2',function(name){
console.log(name,2);
});
queue.tap('3',function(name){
console.log(name,3);
});
queue.callAsync('bearbao',err=>{
console.log(err);
console.timeEnd('cost');
});
// 执行结果
/*
bearbao 1
bearbao 2
bearbao 3
cost: 4.720ms
*/
выполнить
class AsyncParallelHook {
constructor(){
this.listeners = [];
}
tap(name,listener){
this.listeners.push(listener);
}
callAsync(){
this.listeners.forEach(listener=>listener(...arguments));
Array.from(arguments).pop()();
}
}
- Зарегистрируйтесь в TapAsync
Обратите внимание, что здесь есть особое место, как подтвердить, что обратный вызов был выполнен?Последним параметром каждого обратного вызова слушателя является функция обратного вызова.При выполнении обратного вызова текущая функция будет считаться выполненной.
let queue = new AsyncParallelHook(['name']);
console.time('cost');
queue.tapAsync('1',function(name,callback){
setTimeout(function(){
console.log(name, 1);
callback();
},1000)
});
queue.tapAsync('2',function(name,callback){
setTimeout(function(){
console.log(name, 2);
callback();
},2000)
});
queue.tapAsync('3',function(name,callback){
setTimeout(function(){
console.log(name, 3);
callback();
},3000)
});
queue.callAsync('bearbao',err=>{
console.log(err);
console.timeEnd('cost');
});
// 输出结果
/*
bearbao 1
bearbao 2
bearbao 3
cost: 3000.448974609375ms
*/
выполнить
class AsyncParallelHook {
constructor(){
this.listeners = [];
}
tapAsync(name,listener){
this.listeners.push(listener);
}
callAsync(...arg){
let callback = arg.pop();
let i = 0;
let done = ()=>{
if(++i==this.listeners.length){
callback()
}
}
this.listeners.forEach(listener=>listener(...arg,done));
}
}
- Используйте tapPromise
При использовании tapPromise для регистрации слушателей возвращаемое значение каждой функции обратного вызова должно быть экземпляром Promise.
let queue = new AsyncParallelHook(['name']);
console.time('cost');
queue.tapPromise('1',function(name){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(1);
resolve();
},1000)
});
});
queue.tapPromise('2',function(name){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(2);
resolve();
},2000)
});
});
queue.tapPromise('3',function(name){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(3);
resolve();
},3000)
});
});
queue.promise('bearbao').then(()=>{
console.timeEnd('cost');
})
// 执行记过
/*
1
2
3
cost: 3000.448974609375ms
*/
выполнить
class AsyncParallelHook {
constructor(){
this.listeners = [];
}
tapPromise(name,listener){
this.listeners.push(listener);
}
promise(...arg){
let i = 0;
return Promise.all(this.listeners.map(l=>l(arg)))
}
}
5. так сонно так сонно
Это было 1 час случайно.Чтобы получить достижение долголетия, я напишу его здесь сегодня.Следующие методы будут обновлены в течение двух дней.
Эпилог
Если вы считаете, что это нормально, вы можете немного помочь своему пути кодирования, пожалуйста, поставьте лайк и поддержите, спасибо!