Сумасшедший webpack-tapable

Webpack

Услышав о Tapable в течение долгого времени, я, наконец, решил изучить его систематически.

Q1: Проблема, которую решает tapable?

  1. tapable — отдельная библиотека
  2. Эта библиотека активно используется в webpack.
  3. Tapable в основном используется для обработки событий, и проблема, которую он решает, аналогична EventEmitter, но более мощная.

Q2: Какие есть таповые методы?

const {
    SyncHook,
    SyncBailHook,
    SyncWaterfallHook,
    SyncLoopHook,
    AsyncParallelHook,
    AsyncParallelBailHook,
    AsyncSeriesHook,
    AsyncSeriesBailHook,
    AsyncSeriesWaterfallHook 
 } = require("tapable");

Ладно, методов столько, сколько было сказано выше.На первый взгляд, мы с вами под деревом, так что давайте немножко, анализируем, изучаем и разбираемся по одному.

Q3: Что такое SyncHook?

Давайте сначала возьмем пример, например, какими навыками должны овладеть разработчики интерфейса?

Шаг 1: Прежде всего, мы должны дать понять, что группа занимается фронтенд-разработкой.

const {SyncHook}= require('tapable');
const FrontEnd = new SyncHook();

хорошо, два предложения выше, мы создали интерфейсную разработку FrontEnd

Шаг 2: Какие навыки необходимы для освоения фронтенд-разработки, например, веб-пакета, реагируют на него

FrontEnd.tap('webpack',()=>{
  console.log("get webpack")
});
FrontEnd.tap('react',()=>{
  console.log("get react")
});

хорошо, тап выше используется для привязки событий, добавляя два навыка для фронтенд-разработки

Шаг 3: Чтобы овладеть навыками, нужно учиться, поэтому мы должны научиться действиям.

FrontEnd.learn=()=>{
  FrontEnd.call()
};
FrontEnd.learn();

шаг 4: просмотрите результат выполнения

get webpack
get react

Как видите, с помощью приведенных выше вызовов наша фронтенд-разработка научилась реагировать и использовать веб-пакеты.

шаг 5: передать параметры

Я знаю, что FrontEnd — это группа, которой нужно научиться реагировать и использовать веб-пакеты, но с личной точки зрения, кто из разработчиков овладел этими навыками?

const {SyncHook}= require('tapable');
const FrontEnd = new SyncHook();
FrontEnd.tap('webpack',(name)=>{
  console.log(name+" get webpack")
});
FrontEnd.tap('react',(name)=>{
  console.log(name+" get react")
});
FrontEnd.start=(name)=>{
  FrontEnd.call(name)
};
FrontEnd.start('xiaoming');

Измените предыдущий код, добавьте параметр, ожидаемый результат: xxx get response

Шаг 6: просмотрите результат вывода

undefined get webpack
undefined get react

Конечный результат не определен, то есть параметры не передаются в

Шаг 7: Добавьте параметры соглашения в SyncHook

Это потому чтоconst FrontEnd = new SyncHook();При создании SyncHook нет согласованных параметров, просто добавьте к нему параметры следующим образом:

const {SyncHook}= require('tapable');
const FrontEnd = new SyncHook(['name']);// 添加参数约定
FrontEnd.tap('webpack',(name)=>{
  console.log(name+" get webpack")
});
FrontEnd.tap('react',(name)=>{
  console.log(name+" get react")
});
FrontEnd.start=(name)=>{
  FrontEnd.call(name)
};
FrontEnd.start('xiaoming');

Окончательный вывод:

xiaoming get webpack
xiaoming get react

SyncHookСводка

  1. SyncHook в настоящее время больше похож на публикацию по подписке.
  2. Точно так же, как методы add и fire в jquery, но здесь нажмите и вызовите

Q4: Как реализован SyncHook?

Реализация SyncHook относительно проста, что является простейшей публикацией подписки.

class SyncHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tap(name,task){
    this.tasks.push(task);
  }
  call(...args){
    const param =  args.slice(0,this.limit.length);
    this.tasks.forEach(item=>item(...param));
  }
}
  1. предел используется для проверки параметра
  2. задачи используются для сбора подписок
  3. Метод tap используется для добавления методов к задачам.
  4. метод вызова, который проверяет параметры перед выполнением всех подписанных методов

Резюме: принцип относительно прост, технического содержания не так много, в основном это функция синхронного хука.

Q5: Что такое SyncBailHook?

автоматический выключатель, если предыдущее событиеreturn true, то не выполнять следующий или предыдущий пример:

const {SyncBailHook} =require('tapable');
const FrontEnd = new SyncBailHook(['name']);
FrontEnd.tap('webpack',(name)=>{
  console.log(name+" get webpack ")
});
FrontEnd.tap('react',(name)=>{
  console.log(name+" get react")
});
FrontEnd.start=(...args)=>{
  FrontEnd.call(...args)
};
FrontEnd.start('xiaoming');

На этом этапе, если функция изменена с SyncHook на SyncBailHook, результат выполнения не изменится.

Но, подумайте об этом, этому очень легко научиться, поэтому давайте изменим наш пример:

const {SyncBailHook} =require('tapable');
const FrontEnd = new SyncBailHook(['name']);
FrontEnd.tap('webpack',(name)=>{
  console.log(name+" get webpack ")
  return '学不动了啊!';
});
FrontEnd.tap('react',(name)=>{
  console.log(name+" get react")
});
FrontEnd.start=(...args)=>{
  FrontEnd.call(...args)
};
FrontEnd.start('xiaoming');

Выводить только в этот момент:

xiaoming get webpack 

Следующая реакция не выполняется

Суммировать:

  1. Основная проблема, которую решает SyncBailHook — условная блокировка.
  2. Когда событие подписки отвечает определенному мнению, следующий процесс больше не выполняется.
  3. Сценарии приложений, сценарии, в которых сценарии продолжают углубляться, например, a, a+b, a+b+c, a+b+c+d

Q6: Как реализован SyncBailHook?

SyncBailHook тоже очень простой, тот же пример, что и раньше:

class SyncBailHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tap(name,task){
    this.tasks.push(task);
  }
  call(...args){
    const param =  args.slice(0,this.limit.length);
    this.tasks.some(item=>item(...param));// 只改了一行
  }
}

Видно, что он очень похож на вышеописанный SyncHook.Это не что иное, как замена функции выполнения forEach на some, потому что some является блокирующим выполнением.Когда он возвращает true, следующий контент выполняться не будет.

Q7: Что такое SyncWaterfullHook?

Давайте сначала возьмем пример использования, такой как интерфейс, навыки изучаются один за другим, после изучения веб-пакета, а затем учатся реагировать, например:

const {SyncWaterfallHook} = require('tapable');
const FrontEnd = new SyncWaterfallHook(['name']);
FrontEnd.tap('webpack',(name)=>{
  console.log(name+" get webpack ")
  return '学完webpack了,该学react了';
});
FrontEnd.tap('react',(name)=>{
  console.log(name+" get react")
});
FrontEnd.start=(...args)=>{
  FrontEnd.call(...args)
};
FrontEnd.start('xiaoming');

На данный момент вывод:

xiaoming get webpack 
学完webpack了,该学react了 get react
  1. SyncWaterfallHook передаст результат выполнения предыдущей задачи следующей.
  2. Основной сценарий использования — взаимозависимость между логикой обработки
  3. Фактический эффект такой же, как и у метода компоновки в редуксе.

Q8: Как реализован SyncWaterfullHook?

class SyncWaterfallHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tap(name,task){
    this.tasks.push(task);
  }
  call(...args){
    const param =  args.slice(0,this.limit.length);
    const [first,...others] = this.tasks;
    const ret = first(...param);
    others.reduce((pre,next)=>{
      return next(pre);
    },ret)
  }
}

Реализация SyncWaterfallHook также относительно проста.

  1. Просто следуйте инструкциям Redux.
  2. Первый шаг, вывести первое исполнение и получить результат ret
  3. Второй шаг — передать результат ret в качестве параметра сокращения.
  4. Третий шаг — пройти и непрерывно передать параметры следующей функции.

Резюме: SyncWaterfallHook в основном используется в сценариях, где функции зависят от результатов.

Q9: Что такое SyncLoopHook?

В предыдущем примере, если вы не понимаете технологию за один раз, вам придется изучать ее несколько раз, например:

const FrontEnd = new SyncLoopHook(['name']);
let num = 0;
FrontEnd.tap('webpack',(name)=>{
  console.log(name+" get webpack ")
  return ++num === 3?undefined:'再学一次';
});
FrontEnd.tap('react',(name)=>{
  console.log(name+" get react")
});
FrontEnd.start=(...args)=>{
  FrontEnd.call(...args)
};
FrontEnd.start('xiaoming');

Результат вышеописанного выполнения:

xiaoming get webpack 
xiaoming get webpack 
xiaoming get webpack 
xiaoming get react
  1. Задачи SyncLoopHook могут выполняться несколько раз
  2. Вернуть undefined, чтобы остановить выполнение, вернуть non-undefined, чтобы продолжить выполнение текущей задачи.

Резюме: основной сценарий — это одна и та же задача, которую нужно выполнять несколько раз.

Q10: Как реализован SyncLoopHook?

class SyncLoopHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tap(name,task){
    this.tasks.push(task);
  }
  call(...args){
    const param =  args.slice(0,this.limit.length);
    let index = 0;
    while(index<this.tasks.length){
      const result = this.tasks[index](...param);
      if(result === undefined){
        index++;
      }
    }
  }
}
  1. Вышеупомянутая реализация выполняется путем подсчета
  2. Если результат не является неопределенным, индекс нижнего индекса не перемещается.
  3. Если результат не определен, индекс индекса увеличивается.

Вы также можете изменить doWhile для достижения

class SyncLoopHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tap(name,task){
    this.tasks.push(task);
  }
  call(...args){
    const param =  args.slice(0,this.limit.length);
   this.tasks.forEach(task=>{
     let ret;
     do{
      ret = task(...param);
     }while(ret!=undefined)
   })
  }
}
  1. Эта реализация не имеет концепции подписки
  2. Непосредственно пройти группу задач задач и выполнить ее снова, если результат выполнения задачи в группе задач не является неопределенным.

Резюме: Сценарий использования SyncLoopHook относительно редок, но полезно знать

Q11: Что такое AsyncParrallehook?

То, что я узнал ранее, — это синхронные хуки и, что более важно, асинхронные хуки.

Например, одноклассник Сяо Ван сказал, что собирается изучать интерфейс, но вы не знаете, когда он закончил обучение. Вы знаете, что он закончил, только когда он закончит и скажет вам. Например:


const {AsyncParallelHook} = require('tapable');
const FrontEnd = new AsyncParallelHook(['name']);
FrontEnd.tapAsync('webpack',(name,cb)=>{
  setTimeout(() => {
    console.log(name+" get webpack ")
    cb();
  }, 1000);
 
});
FrontEnd.tapAsync('react',(name,cb)=>{
  setTimeout(() => {
    console.log(name+" get react")
    cb();
  }, 1000);
});
FrontEnd.start=(...args)=>{
  FrontEnd.callAsync(...args,()=>{
    console.log("end");
  })
};
FrontEnd.start('小王');

Окончательный вывод:

小王 get webpack 
小王 get react
end
  1. AsyncParralleHook — асинхронный параллельный хук.
  2. Сценарии использования, такие как инициирование запросов к двум интерфейсам одновременно
  3. Примечание. Это событие регистрации больше не является касанием, а является касанием.
  4. Примечание. Это выполнение события больше не является вызовом, а callAsync.
  5. Мы можем различить синхронное и асинхронное публикацию и подписывайтесь в точке
  6. Примечание. Если вы хотите получать уведомление после завершения всех асинхронных исполнений, вам необходимо выполнить cb().

Q12: Как реализован AsyncParralleHook?

class AsyncParallelHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapAsync(name,task){
    this.tasks.push(task);
  }
  callAsync(...args){
    const finalCallBack = args.pop();
    const param =  args.slice(0,this.limit.length);
    let index = 0;
    const done=()=>{
      index++;
      if(index === this.tasks.length){
        finalCallBack();
      }
    }
    this.tasks.forEach(item=>item(...param,done))
  }
}
  1. AsyncParallelHook проще всего, если считать
  2. Добавить счетчик на экземпляр
  3. Затем пройдите задачи, когда количество успешных задач совпадает с общим количеством задач, выполните finalCallBack

Резюме: проблема, решаемая AsyncParallelHook, аналогична проблеме promise.all, который используется для решения проблемы асинхронного параллелизма.

Q13: Как обещает обещания AsyncParrallehook (2)?

Хотя предыдущее использование: AsyncParralleHook может решить асинхронность, он не использует обещания и не имеет концепции обещаний класса.

const {AsyncParallelHook} = require('tapable');
const FrontEnd = new AsyncParallelHook(['name']);
FrontEnd.tapPromise('webpack',(name)=>{
  return new Promise((resolve)=>{
    setTimeout(() => {
      console.log(name+" get webpack ")
      resolve();
    }, 1000);
  })
});
FrontEnd.tapPromise('react',(name,cb)=>{
  return new Promise((resolve)=>{
    setTimeout(() => {
      console.log(name+" get react ")
      resolve();
    }, 1000);
  })
});
FrontEnd.start=(...args)=>{
  FrontEnd.promise(...args).then(()=>{
    console.log("end");
  })
};
FrontEnd.start('小王');

После вызова вышеуказанного API вывод:

小王 get webpack 
小王 get react 
end
  1. Примечание. В настоящее время метод связывания событий называется tapPromise.
  2. Примечание. Метод, выполняющий событие в это время, называется обещанием.

Суммировать:

  1. Существует три метода привязки событий для tapable: tap, tapAsync, tapPromise.
  2. Существует три метода выполнения события для tapable: call, callAsync, promise.

Q14: Как реализована версия обещания AsyncParralleHook (2)?

class AsyncParallelHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapPromise(name,task){
    this.tasks.push(task);
  }
  promise(...args){
    const param =  args.slice(0,this.limit.length);
    const tasks = this.tasks.map(task=>task(...param));
    return Promise.all(tasks)
  }
}
  1. Суть в том, чтобы реализовать два метода: tapPromise и promise.
  2. По сути, tapPromise не сильно отличается от предыдущего tap (простая проблема реализации)
  3. Promise на самом деле возвращает Promise.all

Q15: Что такое AsyncParallelBailHook?

AsyncParallelBailHook Этот хук отличается от предыдущего хука. Согласно предыдущему примеру:

  1. Одноклассник Сяо Ван сказал, что собирается изучать интерфейс, но вы не знаете, когда он закончит учебу, только когда он закончит и расскажет вам, вы узнаете, что он закончил.
  2. Ван выучил веб-пакет, школьный коллапс, чтобы сказать вам
  3. Когда вы услышали, что школа Сяо Вана развалилась, вы подумали, что он не сможет продолжать учиться, поэтому вы сказали здоровяку, что школа Сяо Вана развалилась.
  4. Но Сяо Ван также научился реагировать в то же время, но закончил его сквозь стиснутые зубы.
  5. Хотя вы закончили обучение, вы уже объявили, что Сяо Ван упал в обморок, и это позор, поэтому вы этого не знаете.

Это то, что обрабатывает AsyncParallelBailHook

const {AsyncParallelBailHook} = require('tapable');
const FrontEnd = new AsyncParallelBailHook(['name']);
FrontEnd.tapPromise('webpack',(name)=>{
  return new Promise((resolve,reject)=>{
    setTimeout(() => {
      console.log(name+" get webpack ")
      reject('小王学崩了!');
    }, 1000);
  })
});
FrontEnd.tapPromise('react',(name,cb)=>{
  return new Promise((resolve)=>{
    setTimeout(() => {
      console.log(name+" get react ")
      resolve();
    }, 2000);
  })
});
FrontEnd.start=(...args)=>{
  FrontEnd.promise(...args).then(()=>{
    console.log("end");
  },(err)=>{
    console.log("听说:",err)
  })
};
FrontEnd.start('小王');

Результат выполнения приведенного выше кода:

小王 get webpack 
听说: 小王学崩了!
小王 get react 
  1. В приведенном выше примере первая параллельная задача возвращает отклонение.
  2. Пока отклонение не неопределенно, оно перейдет непосредственно к улову обещания.
  3. Асинхронные задачи, реакция будет по-прежнему выполняться, но не обрабатываться после успеха

Давайте посмотрим на другой пример:

const {AsyncParallelBailHook} = require('tapable');
const FrontEnd = new AsyncParallelBailHook(['name']);
FrontEnd.tapPromise('webpack',(name)=>{
  return new Promise((resolve,reject)=>{
    setTimeout(() => {
      console.log(name+" get webpack ")
      reject();
    }, 1000);
  })
});
FrontEnd.tapPromise('react',(name,cb)=>{
  return new Promise((resolve)=>{
    setTimeout(() => {
      console.log(name+" get react ")
      resolve();
    }, 2000);
  })
});
FrontEnd.start=(...args)=>{
  FrontEnd.promise(...args).then(()=>{
    console.log("end");
  },(err)=>{
    console.log("听说:",err)
  })
};
FrontEnd.start('小王');

Изменил 1 строку на указанную выше, то есть содержимое отклонения пусто, а вывод такой:

小王 get webpack 
小王 get react 
end
  1. В этот момент, даже если будет вызвано отклонение, оно не попадет в ловушку.
  2. reject возвращает пустое значение, и последующие задачи будут выполняться как обычно

Суммировать:

  1. AsyncParallelBailHook, если он возвращает истинное значение, он попадет прямо в ловушку
  2. Все задачи будут выполнены независимо от возвращаемого результата
  3. Основной сценарий — запрашиваются три интерфейса параллельно, и любой из них может вернуть результат, пока он возвращает, возврат будет обрабатываться (catch)
  4. Если он используется для обработки синхронизации, он имеет тот же эффект, что и SyncBailHook.
  5. Если tapSync обрабатывается, окончательный обратный вызов, который возвращает true, не будет выполнен.
  6. Если вы имеете дело с обещаниями и встречаете rejcet(true), сразу переходите к catch

Q16: Как реализован AsyncParallelBailHook?

Этот AsyncParallelBailHook какое-то время действительно выжигает мозги

class AsyncParallelBailHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapPromise(name,task){
    this.tasks.push(task);
  }
  promise(...args){
    const param =  args.slice(0,this.limit.length);
    const tasks = this.tasks.map(task=>{
      return new Promise((resolve,reject)=>{
        task(...param).then((data)=>{
          resolve(data);
        },(err)=>{
          err? reject(err):resolve();
        });
      })
    });
    return Promise.all(tasks)
  }
}
  1. При нормальных обстоятельствах любая задача в promise.all reject войдет в унифицированный catch.
  2. Но что нам нужно, так это судить, следует ли идти как catch в соответствии со значением reject.
  3. Таким образом, мы обертываем еще один слой обещания в дополнение к исходной задаче.
  4. Если отклонение истинно, выполнить отклонение
  5. Если reject имеет значение false, выполнить resolve, как будто ничего не произошло

Q17: Что такое AsyncSeriesHook?

Я говорил об асинхронном параллелизме. Теперь пришло время поговорить об асинхронной сериализации. Например, Сяо Ван научился реагировать после изучения веб-пакета. :

const {AsyncSeriesHook} = require('tapable');
const FrontEnd = new AsyncSeriesHook(['name']);
console.time('webpack');
console.time('react');
FrontEnd.tapPromise('webpack',(name,cb)=>{
  return new Promise((resolve,reject)=>{
    setTimeout(() => {
      console.log(name+" get webpack ")
      console.timeEnd('webpack');
      resolve();
    }, 1000);
  })
});
FrontEnd.tapPromise('react',(name,cb)=>{
  return new Promise((resolve)=>{
    setTimeout(() => {
      console.log(name+" get react ")
      console.timeEnd('react');
      resolve();
    }, 1000);
  })
});
FrontEnd.start=(...args)=>{
  FrontEnd.promise(...args).then(()=>{
    console.log("end");
  })
};
FrontEnd.start('小王');

Результат выполнения приведенного выше кода:

小王 get webpack 
webpack: 1010.781ms
小王 get react 
react: 2016.598ms
end
  1. Две асинхронные задачи становятся последовательными
  2. Со времени можно сделать вывод, что общее время двух асинхронных задач 1 с после сериализации становится 2 с.

Резюме: проблема, решаемая AsyncSeriesHook, заключается в асинхронной сериализации.Например, os.cpus() узла ограничен, и задачи могут выполняться пакетами, что гарантирует производительность.

Q18: Как реализован AsyncSeriesHook?

class AsyncSeriesHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapPromise(name,task){
    this.tasks.push(task);
  }
  promise(...args){
    const param =  args.slice(0,this.limit.length);
    const [first,...others] = this.tasks;
    return others.reduce((pre,next)=>{
      return pre.then(()=>next(...param))
    },first(...param))
  }
}
  1. Ядром реализации является серийный номер обещания.
  2. Выньте первую задачу, выполните, чтобы получить экземпляр обещания, а затем пройдите через сокращение

Q19: Что такое AsyncSeriesBailHook?

Тем не менее в предыдущем примере, если Сяо Ван изучит интерфейс и полностью сдастся после изучения webapck, то ему не нужно изучать следующие реакции.

const {AsyncSeriesBailHook} = require('tapable');
const FrontEnd = new AsyncSeriesBailHook(['name']);
console.time('webpack');
console.time('react');
FrontEnd.tapPromise('webpack',(name,cb)=>{
  return new Promise((resolve,reject)=>{
    setTimeout(() => {
      console.log(name+" get webpack ")
      console.timeEnd('webpack');
      reject('小王彻底放弃了');
    }, 1000);
  })
});
FrontEnd.tapPromise('react',(name,cb)=>{
  return new Promise((resolve)=>{
    setTimeout(() => {
      console.log(name+" get react ")
      console.timeEnd('react');
      resolve();
    }, 1000);
  })
});
FrontEnd.start=(...args)=>{
  FrontEnd.promise(...args).then(()=>{
    console.log("end");
  }).catch((err)=>{
    console.log("err",err)
  })
};
FrontEnd.start('小王');

Приведенный выше код выводит:

小王 get webpack 
webpack: 1010.518ms
err 小王彻底放弃了
  1. Приведенный выше код выполняется только для веб-пакета
  2. AsyncSeriesBailHook, если задача возвращается или отклоняется, она блокируется

Сценарий: в основном асинхронный последовательный, если результат выполнения задачи отклоняется или возвращается, то следующее больше не будет выполняться.

Q20: Как реализовать AsyncSeriesBailHook?

class AsyncSeriesBailHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapPromise(name,task){
    this.tasks.push(task);
  }
  promise(...args){
    const param =  args.slice(0,this.limit.length);
    const [first,...others] = this.tasks;
    return new Promise((resolve,reject)=>{
      others.reduce((pre,next,index,arr)=>{
        return pre
          .then(()=>next(...param))
          .catch((err=>{
            arr.splice(index,arr.length-index);
            reject(err);
          })).then(()=>{
            (index+1 === arr.length) && resolve();
          })
      },first(...param))
    })
  }
}

AsyncSeriesBailHook гораздо сложнее реализовать.

  1. Сначала оберните слой обещания снаружи, уменьшите
  2. Когда какая-либо подзадача попадает в catch, четвертый параметр arr редукции обрезается, чтобы она больше не могла идти вниз, то есть продолжение редукции останавливается.
  3. При этом добавить пост-потом после всех обещаний проверить, все ли выполнения завершены.
  4. Зачем использовать index+1, потому что пост должен быть последним заданием, но индекс обхода все еще находится в предыдущем индексе, поэтому просто добавьте 1.

Q21: Что такое AsyncSeriesWaterfallHook?

Syncwaterfallhook уже узнал, только результат предыдущего исполнения будет передан следующему исполнению функции исполнения, и разница между Asyncserieswaterfallhook - это то, что один синхронизирован асинхронными

В частности, например, есть только один учебник, который Сяо Ван может выучить до того, как его выучит Сяо Чжан.

const FrontEnd = new AsyncSeriesWaterfallHook(['name']);
FrontEnd.tapAsync('webpack',(name,cb)=>{
    setTimeout(() => {
      console.log(name+" get webpack ")
      cb(null,'小李');
    }, 1000);
});
FrontEnd.tapAsync('webpack',(name,cb)=>{
  setTimeout(() => {
    console.log(name+" get webpack ")
    cb(null,'小张');
  }, 1000);
});
FrontEnd.tapAsync('webpack',(name,cb)=>{
  setTimeout(() => {
    console.log(name+" get webpack ")
    cb(null,'小红');
  }, 1000);
});
FrontEnd.start=(...args)=>{
  FrontEnd.callAsync(...args,(data)=>{
    console.log("全学完了",)
  })
};
FrontEnd.start('小王');

Приведенный выше код, окончательный вывод:

小王 get webpack 
小李 get webpack 
小张 get webpack 
全学完了

Резюме: использование этого согласуется с использованием SyncWaterFallHook.

Q22: Как реализован AsyncSeriesWaterfallHook?

class AsyncSeriesWaterfallHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapAsync(name,task){
    this.tasks.push(task);
  }
  callAsync(...args){
    const param =  args.slice(0,this.limit.length);
    const finalCallBack = args.pop();
    let index = 0;
    const next = (err,data)=>{
      const task = this.tasks[index];
      if(!task)return finalCallBack();
      if(index === 0){
        task(...param,next)
      }else{
        task(data,next)
      }
      index++;
    }
    next();
  }
}
  1. В основном путем инкапсуляции функции обратного вызова
  2. Затем непрерывно вызывать задачи в очереди задач, а при вызове передавать ту же функцию обратного вызова в

Обещанная версия реализована следующим образом:

class AsyncSeriesWaterfallHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapPromise(name,task){
    this.tasks.push(task);
  }
  promise(...args){
    const param =  args.slice(0,this.limit.length);
    const [first,...others] = this.tasks;
    return others.reduce((pre,next)=>{
      return pre.then((data)=>{
        return data?next(data):next(...param);
      })
    },first(...param))
  }
}
  1. Реализация промисов относительно проста
  2. В основном, чтобы увидеть, есть ли содержимое в методе then, если да, передать следующую функцию, если нет, использовать начальный параметр

Суммировать

  1. Каждый AsyncHook Tapable поддерживает tap, tapAsync, tapPromise одновременно.
  2. Tapable в основном решает проблему потока событий, и сценарии, используемые каждым хуком, разные.
  3. Tapable в основном используется в каждом жизненном цикле веб-пакета, поэтому конкретная практика должна сочетаться с принципом веб-пакета.

Цитировать

руководство по использованию