AsyncParallelHook: 異步 並行webpack
從tapable生產的腳原本看AsyncParallelHookweb
先來看 tap + callAsyncpromise
const { AsyncParallelHook } = require("tapable"); let queue1 = new AsyncParallelHook(['name']); console.time('cost'); queue1.tap('1', function (name) { console.log(name, 1); }); queue1.tap('2', function (name) { console.log(name, 2); }); queue1.callAsync('webpack', err => { console.timeEnd('cost'); }); // 執行結果 webpack 1 webpack 2 cost: 4.520ms
看生產的源碼就知道:這種模式屬於順序執行,一個報錯當即回調:異步
"use strict"; var _context; var _x = this._x; do { var _counter = 2; var _done = () => { _callback(); }; if (_counter <= 0) break; var _fn0 = _x[0]; var _hasError0 = false; try { _fn0(________name); } catch (_err) { _hasError0 = true; if (_counter > 0) { _callback(_err); _counter = 0; } } if (!_hasError0) { if (--_counter === 0) _done(); } if (_counter <= 0) break; var _fn1 = _x[1]; var _hasError1 = false; try { _fn1(________name); } catch (_err) { _hasError1 = true; if (_counter > 0) { _callback(_err); _counter = 0; } } if (!_hasError1) { if (--_counter === 0) _done(); } } while (false);
接着看 tapAsync + callAsync函數
let queue2 = new AsyncParallelHook(['name']); console.time('cost1'); queue2.tapAsync('1', function (name, cb) { setTimeout(() => { console.log(name, 1); cb(); }, 1000); }); queue2.tapAsync('2', function (name, cb) { setTimeout(() => { console.log(name, 2); cb(); }, 2000); }); queue2.callAsync('webpack', () => { console.log('over'); console.timeEnd('cost1'); }); // 執行結果 /* webpack 1 webpack 2 over time: 3004.411ms */
生產的源碼以下:ui
"use strict"; var _context; var _x = this._x; do { var _counter = 2; var _done = () => { _callback(); }; if (_counter <= 0) break; var _fn0 = _x[0]; _fn0(name, _err0 => { if (_err0) { if (_counter > 0) { _callback(_err0); _counter = 0; } } else { if (--_counter === 0) _done(); } }); if (_counter <= 0) break; var _fn1 = _x[1]; _fn1(name, _err1 => { if (_err1) { if (_counter > 0) { _callback(_err1); _counter = 0; } } else { if (--_counter === 0) _done(); } }); } while (false);
最後看 tapPromise+ promisethis
執行code
const { AsyncParallelBailHook } = require("tapable"); let queue3 = new AsyncParallelBailHook(['name']); console.time('cost3'); queue3.tapPromise('1', function (name, cb) { return new Promise(function (resolve, reject) { setTimeout(() => { console.log(name, 1); resolve(); }, 1000); }); }); queue3.tapPromise('2', function (name, cb) { return new Promise(function (resolve, reject) { setTimeout(() => { console.log(name, 2); reject('wrong');// reject()的參數是一個不爲null的參數時,最後的回調就不會再調用了 }, 2000); }); }); queue3.promise('webpack') .then(() => { console.log('over'); console.timeEnd('cost3'); }, () => { console.log('error'); console.timeEnd('cost3'); }); // 執行結果: /* webpack 1 webpack 2 error cost3: 2009.970ms webpack 3 */
源碼:對象
"use strict"; return new Promise((_resolve, _reject) => { var _sync = true; function _error(_err) { if (_sync) _resolve(Promise.resolve().then(() => { throw _err; })); else _reject(_err); }; var _context; var _x = this._x; var _results = new Array(2); var _checkDone = () => { for (var i = 0; i < _results.length; i++) { var item = _results[i]; if (item === undefined) return false; if (item.result !== undefined) { _resolve(item.result); return true; } if (item.error) { _error(item.error); return true; } } return false; } do { var _counter = 2; var _done = () => { _resolve(); }; if (_counter <= 0) break; var _fn0 = _x[0]; var _hasResult0 = false; var _promise0 = _fn0(name); if (!_promise0 || !_promise0.then) throw new Error('Tap function (tapPromise) did not return promise (returned ' + _promise0 + ')'); _promise0.then(_result0 => { _hasResult0 = true; if (_counter > 0) { if (0 < _results.length && (_result0 !== undefined && (_results.length = 1), (_results[0] = { result: _result0 }), _checkDone())) { _counter = 0; } else { if (--_counter === 0) _done(); } } }, _err0 => { if (_hasResult0) throw _err0; if (_counter > 0) { if (0 < _results.length && ((_results.length = 1), (_results[0] = { error: _err0 }), _checkDone())) { _counter = 0; } else { if (--_counter === 0) _done(); } } }); if (_counter <= 0) break; if (1 >= _results.length) { if (--_counter === 0) _done(); } else { var _fn1 = _x[1]; var _hasResult1 = false; var _promise1 = _fn1(name); if (!_promise1 || !_promise1.then) throw new Error('Tap function (tapPromise) did not return promise (returned ' + _promise1 + ')'); _promise1.then(_result1 => { _hasResult1 = true; if (_counter > 0) { if (1 < _results.length && (_result1 !== undefined && (_results.length = 2), (_results[1] = { result: _result1 }), _checkDone())) { _counter = 0; } else { if (--_counter === 0) _done(); } } }, _err1 => { if (_hasResult1) throw _err1; if (_counter > 0) { if (1 < _results.length && ((_results.length = 2), (_results[1] = { error: _err1 }), _checkDone())) { _counter = 0; } else { if (--_counter === 0) _done(); } } }); } } while (false); _sync = false; });
以上是熔斷型號的AsyncParallelHook,正常的AsyncParallelHook如下:源碼
const { AsyncParallelHook } = require("tapable"); let queue3 = new AsyncParallelHook(['name']); console.time('cost3'); queue3.tapPromise('1333333333', function (name, cb) { return new Promise(function (resolve, reject) { setTimeout(() => { console.log(name, 1); resolve('qwer'); }, 1000); }); }); queue3.tapPromise('222222222', function (name, cb) { return new Promise(function (resolve, reject) { setTimeout(() => { console.log(name, 2); resolve('tyui'); }, 2000); }); }); queue3.promise('webpack') .then((al) => { console.log('over'+al); console.timeEnd('cost3'); }, () => { console.log('error'); console.timeEnd('cost3'); }); /* webpack 1 webpack 2 over cost3: 3007.925ms */
轉換後的源碼以下所示:
"use strict"; return new Promise((_resolve, _reject) => { var _sync = true; function _error(_err) { if (_sync) _resolve(Promise.resolve().then(() => { throw _err; })); else _reject(_err); }; var _context; var _x = this._x; do { var _counter = 2; var _done = () => { _resolve(); }; if (_counter <= 0) break; var _fn0 = _x[0]; var _hasResult0 = false; var _promise0 = _fn0(name); if (!_promise0 || !_promise0.then) throw new Error('Tap function (tapPromise) did not return promise (returned ' + _promise0 + ')'); _promise0.then(_result0 => { _hasResult0 = true; if (--_counter === 0) _done(); }, _err0 => { if (_hasResult0) throw _err0; if (_counter > 0) { _error(_err0); _counter = 0; } }); if (_counter <= 0) break; var _fn1 = _x[1]; var _hasResult1 = false; var _promise1 = _fn1(name); if (!_promise1 || !_promise1.then) throw new Error('Tap function (tapPromise) did not return promise (returned ' + _promise1 + ')'); _promise1.then(_result1 => { _hasResult1 = true; if (--_counter === 0) _done(); }, _err1 => { if (_hasResult1) throw _err1; if (_counter > 0) { _error(_err1); _counter = 0; } }); } while (false); _sync = false; });
看以看出對於 tapPromise,綁定的函數的返回值必定要是一個promise,不然報錯:
Tap function (tapPromise) did not return promise
對於tapPromise 添加的綁定,於callAsync呢?tapPromise +callAsync
const { AsyncParallelHook } = require("tapable"); let queue3 = new AsyncParallelHook(['name']); console.time('cost3'); queue3.tapPromise('1333333333', function (name, cb) { return new Promise(function (resolve, reject) { setTimeout(() => { console.log(name, 1); resolve('qwer'); }, 1000); }); }); queue3.tapPromise('222222222', function (name, cb) { return new Promise(function (resolve, reject) { setTimeout(() => { console.log(name, 2); resolve('tyui'); }, 2000); }); }); queue3.callAsync('webpack', () => { console.log('over'); console.timeEnd('cost3'); });
生產源碼:
"use strict"; var _context; var _x = this._x; do { var _counter = 2; var _done = () => { _callback(); }; if (_counter <= 0) break; var _fn0 = _x[0]; var _hasResult0 = false; var _promise0 = _fn0(name); if (!_promise0 || !_promise0.then) throw new Error('Tap function (tapPromise) did not return promise (returned ' + _promise0 + ')'); _promise0.then(_result0 => { _hasResult0 = true; if (--_counter === 0) _done(); }, _err0 => { if (_hasResult0) throw _err0; if (_counter > 0) { _callback(_err0); _counter = 0; } }); if (_counter <= 0) break; var _fn1 = _x[1]; var _hasResult1 = false; var _promise1 = _fn1(name); if (!_promise1 || !_promise1.then) throw new Error('Tap function (tapPromise) did not return promise (returned ' + _promise1 + ')'); _promise1.then(_result1 => { _hasResult1 = true; if (--_counter === 0) _done(); }, _err1 => { if (_hasResult1) throw _err1; if (_counter > 0) { _callback(_err1); _counter = 0; } }); } while (false);
能夠看出 於promise方式基本同樣,只不過是這裏最後返回的不是一個promise對象,沒法有then調用