tapable學習筆記之AsyncParallelHook

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調用

相關文章
相關標籤/搜索