javascript(js)中封装同时兼容promise和callback的函数(方法)

date: 2018.03.09; modification:2018.03.09

目录:

1 前提约定

此方法是从js的react-native-webrtc库中学来的, 它原版的实现感觉有些复杂, 这里稍微简化一下, 约定一些限制:

2 实现方法

此实现的方法很简单, 功能函数都采用promise来实现, 然后在其外面再封装一层withLegacyCallback, 使用的时候, 调用withLegacyCallback封装后的函数, 在该封装内部, 判断调用时传入的最后一个参数, 如果最后一个参数类型为函数的话, 则认为是callback方式, 走callback流程, 否则直接调用(即返回promise).

3 实现代码

具体实现如下:


    // 封装兼容性的函数
    function withLegacyCallback(func) {
        return function(...args) {                              // 返回封装后的函数.
            let callback = args[args.length - 1];               // 如果是callback模式, 最后一个参数需要是callback函数.

            // If legacy callback mode
            if (args.length >= 1
                    && typeof callback === 'function') {
                return func(...args.slice(0, args.length - 1))  // 调用实际的功能函数.
                .then((res) => {
                    callback(null, res);                        // 成功
                }).catch((err) => {
                    callback(err);                              // 失败
                });
            }

            // Promise mode
            return func(...args);                               // Promise模式, 直接return.
        };
    }


    // 被封装的功能函数
    function prDelay(ms, shouldOk) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                if (shouldOk) {
                    resolve({code: 200, data: 'OK'});
                } else {
                    reject({code: 404, data: 'Not found'});
                }
            }, ms);
        });
    }

    // 封装后的函数
    const delay = withLegacyCallback(prDelay);




    // 测试用例:
    // 本用例分别模拟promise模式成功/失败, 和callback模式成功/失败的情况.
    // 如果本用例通过, 结果应该都显示绿色的[OK], 如果显示红色的[FAIL], 则表示测试失败.
    function SHOULD(...args) {
        console.log('', ...args, '');
    }

    function OK(...args) {
        console.log('    [OK]  ', ...args, '');
    }

    function FAIL(...args) {
        console.log('    [FAIL]', ...args, '');
    }

    SHOULD('promise-mode: should be OK');
    delay(1000, true)
    .then((res) => {
        OK('Should OK, res:', res);
    }).then(() => {
        SHOULD('promise-mode: should be error');
        return delay(1000, false);
    }).then((res) => {
        FAIL('Should not be here, res:', res);
    }).catch((err) => {
        OK('Should be err here:', err);
    }).then((res) => {
        SHOULD('callback-mode: should be OK');
        delay(1000, true, (err, res) => {
            if (err) {
                FAIL('Should not be here, res:', res);
            } else {
                OK('Should OK, res:', res);
            }

            SHOULD('callback-mode: should be FAIL');
            delay(1000, false, (err, res) => {
                if (err) {
                    OK('Should be err here:', err);
                } else {
                    FAIL('Should not be here, res:', res);
                }
            });
        });
    })

注意: 如果被封装的功能函数为对象的方法, 需要进行bind this. 如:

this.createOffer = withLegacyCallback(this.createOffer.bind(this));