function Tapable() {
this._plugins = {};
}
function copyProperties(from, to) {
for (var key in from)
to[key] = from[key];
return to;
}
//同步串行钩子
Tapable.prototype.applyPlugins = function applyPlugins(name) {
if (!this._plugins[name]) return;
var args = Array.prototype.slice.call(arguments, 1);
var plugins = this._plugins[name];
for (var i = 0; i < plugins.length; i++)
plugins[i].apply(this, args);
};
//同步瀑布钩子
Tapable.prototype.applyPluginsWaterfall = function applyPluginsWaterfall(name, init) {
if (!this._plugins[name]) return init;
var args = Array.prototype.slice.call(arguments, 1);
console.info(args)
var plugins = this._plugins[name];
var current = init;
for (var i = 0; i < plugins.length; i++) {
args[0] = current;
current = plugins[i].apply(this, args);
}
return current;
};
//同步竞争钩子
Tapable.prototype.applyPluginsBailResult = function applyPluginsBailResult(name) {
if (!this._plugins[name]) return;
var args = Array.prototype.slice.call(arguments, 1);
var plugins = this._plugins[name];
for (var i = 0; i < plugins.length; i++) {
var result = plugins[i].apply(this, args);
if (typeof result !== "undefined") {
return result;
}
}
};
//异步串行钩子(主动调用cb通知下个插件执行)
Tapable.prototype.applyPluginsAsyncSeries = Tapable.prototype.applyPluginsAsync = function applyPluginsAsyncSeries(name) {
var args = Array.prototype.slice.call(arguments, 1);
var callback = args.pop();
var plugins = this._plugins[name];
if (!plugins || plugins.length === 0) return callback();
var i = 0;
var _this = this;
args.push(copyProperties(callback, function next(err) {
if (err) return callback(err);
i++;
if (i >= plugins.length) {
return callback();
}
plugins[i].apply(_this, args);
}));
plugins[0].apply(this, args);
};
//类似于promise.all
Tapable.prototype.applyPluginsParallel = function applyPluginsParallel(name) {
var args = Array.prototype.slice.call(arguments, 1);
var callback = args.pop();
if (!this._plugins[name] || this._plugins[name].length === 0) return callback();
var plugins = this._plugins[name];
var remaining = plugins.length;
args.push(copyProperties(callback, function (err) {
if (remaining < 0) return; // ignore
if (err) {
remaining = -1;
return callback(err);
}
remaining--;
if (remaining === 0) {
return callback();
}
}));
for (var i = 0; i < plugins.length; i++) {
plugins[i].apply(this, args);
if (remaining < 0) return;
}
};
Tapable.prototype.applyPluginsAsyncSeriesBailResult = function applyPluginsAsyncSeriesBailResult(name) {
var args = Array.prototype.slice.call(arguments, 1);
var callback = args.pop();
if (!this._plugins[name] || this._plugins[name].length === 0) return callback();
var plugins = this._plugins[name];
var i = 0;
var _this = this;
args.push(copyProperties(callback, function next() {
if (arguments.length > 0) return callback.apply(null, arguments);
i++;
if (i >= plugins.length) {
return callback();
}
plugins[i].apply(_this, args);
}));
plugins[0].apply(this, args);
};
const wait = (name, delay) => function (a, b, cb) {
setTimeout(() => {
console.log(name, a, b);
cb(null, 'err');
}, delay)
}
const call = (name) => function (a, b, cb) {
console.log(name, a, b);
// return cb
// cb(null, 'err');
cb('err');
}
const t = new Tapable()
t._plugins.emit = [wait('a', 1000),
wait('b', 500),]
t._plugins.call = [call('a'),
call('b'),]
// t.applyPlugins("emit", 1, 2, (a, b) => console.log('end', a, b))
// t.applyPluginsWaterfall("call", 1, 2, (a, b) => console.log('end', a, b))
// t.applyPluginsBailResult("call", 1, 2, (a, b) => console.log('end', a, b))
// t.applyPluginsAsync("emit", 1, 2, (a, b) => console.log('end', a, b))
t.applyPluginsParallel("call", 1, 2, (a, b) => console.log('end', a, b))
// t.applyPluginsAsyncSeriesBailResult("call", 1, 2, (a, b) => console.log('end', a, b))
console