Как можно просто использовать веб-пакет, понять, что ядро ​​можно использовать в ядре?

внешний интерфейс React.js Promise Webpack
Как можно просто использовать веб-пакет, понять, что ядро ​​можно использовать в ядре?

предисловие

Зачем нам нужно изучать 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 час случайно.Чтобы получить достижение долголетия, я напишу его здесь сегодня.Следующие методы будут обновлены в течение двух дней.

Эпилог

Если вы считаете, что это нормально, вы можете немного помочь своему пути кодирования, пожалуйста, поставьте лайк и поддержите, спасибо!