【问题标题】:Conditionally chain functions in JavaScriptJavaScript 中的条件链函数
【发布时间】:2016-02-26 06:36:00
【问题描述】:

我正在尝试重构以下 node.js 代码。

每个案例都会生成一个缩略图,将一组不同的 GraphicMagic 转换链接到图像。

switch(style.name) {
    case 'original':
        gm(response.Body)
            .setFormat('jpg').autoOrient().resize(style.w, style.h, style.option)
            .toBuffer(function(err, buffer) { if (err) { next(err); } else { next(null, buffer); } });
        break;
    case 'large':
        gm(response.Body)
            .setFormat('jpg').autoOrient().resize(style.w, style.h, style.option)
            .quality(style.quality)
            .strip().interlace('Plane')
            .toBuffer(function(err, buffer) { if (err) { next(err); } else { next(null, buffer); } });
        break;
    case 'medium':
        gm(response.Body)
            .setFormat('jpg').autoOrient().resize(style.w, style.h, style.option)
            .crop(style.w, style.h, style.crop.x_offset, style.crop.y_offset)
            .repage('+')
            .strip().interlace('Plane')
            .toBuffer(function(err, buffer) { if (err) { next(err); } else { next(null, buffer); } });
        break;
    case 'small':
        gm(response.Body)
            .setFormat('jpg').autoOrient().resize(style.w, style.h, style.option)
            .crop(style.w, style.h, style.crop.x_offset, style.crop.y_offset).repage('+')
            .quality(style.quality)
            .strip().interlace('Plane')
            .toBuffer(function(err, buffer) { if (err) { next(err); } else { next(null, buffer); } });
        break;
}

但是,所有案例在链接的开头和结尾都共享许多转换,因此有重构的空间。我尝试使用以下方法进行重构,但代码似乎不正确:

gm(response.Body)
.setFormat('jpg').autoOrient().resize(style.w, style.h, style.option, function(err, response) {
    if (style.name === 'original'){
        return response;
    } else if (style.name === 'large'){
        return response.quality(style.quality)
    } else if (style.name === 'medium'){
        return response.crop(style.w, style.h, style.crop.x_offset, style.crop.y_offset).repage('+')
    } else if (style.name === 'small'){
        return response.crop(style.w, style.h, style.crop.x_offset, style.crop.y_offset).repage('+').quality(style.quality)
    }
}).(function(response) {
    return (stryle.name !== 'original') ? response.strip().interlace('Plane') : return response;
}).(function(argument) {
    return response.toBuffer(function(err, buffer) { if (err) { next(err); } else { next(null, buffer); } });
});

【问题讨论】:

  • ).(
  • 另外,一个更易读的对象{"original":resp1, "normal":resp2, etc...}
  • 呃,我没有看到 resize 在第一个 sn-p 中接受 function(err, response) 回调?

标签: javascript node.js graphicsmagick


【解决方案1】:

我为这些用例写了一个小的 js 助手:https://github.com/sms-system/conditional-chain

借助此工具,您可以根据条件链接可选方法。 代码将更加可控和可读。

cond(gm(response.Body)
  .setFormat('jpg')
  .autoOrient()
  .resize(style.w, style.h, style.option))

.if(style.name == 'medium' || style.name == 'small', gm => gm
  .crop(style.w, style.h, style.crop.x_offset, style.crop.y_offset)
  .repage('+'))

.if(style.name == 'large' || style.name == 'small', gm => gm
  .quality(style.quality))

.if(style.name != 'original', gm => gm
  .strip()
  .interlace('Plane'))

.end().toBuffer(next)

【讨论】:

    【解决方案2】:

    我根本不会去switch

    这里根本没有理由使用链接。做吧

    // if (!/^(original|large|medium|small)$/.test(style.name)) throw new Error(…);
    var x = gm(response.Body)
             .setFormat('jpg')
             .autoOrient()
             .resize(style.w, style.h, style.option);
    if (style.name == "medium" || style.name == "small")
        x = x.crop(style.w, style.h, style.crop.x_offset, style.crop.y_offset)
             .repage('+');
    if (style.name == "large" || style.name == "small")
        x = x.quality(style.quality);
    if (style.name == "large" || style.name == "medium" || style.name == "small")
    // possibly better than if (style.name != "original")
        x = x.strip()
             .interlace('Plane');
    x.toBuffer(next);
    

    但是,如果您有大量选项以致无法阅读,最好将函数中的每个转换都分解出来:

    function resizedJpg(x) {
        return x.setFormat('jpg').autoOrient().resize(style.w, style.h, style.option);
    }
    function cropped(x) {
        return x.crop(style.w, style.h, style.crop.x_offset, style.crop.y_offset).repage('+');
    }
    function withQuality(x) {
        return x.quality(style.quality);
    }
    function stripped(x) {
        return x.strip().interlace('Plane');
    }
    

    然后分别应用:

    ({
        original: [resizedJpg],
        large:    [resizedJpg,          withQuality, stripped],
        medium:   [resizedJpg, cropped,              stripped],
        small:    [resizedJpg, cropped, withQuality, stripped]
    }[style.name]).reduce(function(x, trans) {
        return trans(x);
    }, gm(response.Body)).toBuffer(next);
    

    【讨论】:

    • 感谢您的精彩回答!对于第一种方法,由于我们不是一次链接所有方法并使用中间变量 x,它会单独运行 gm 转换(在 if 语句之前一次,在 if 语句之后两次),还是在我们调用 @ 时一次执行所有这些转换987654325@?
    • 我担心的是,多次调用转换也会在图像上多次运行 gm,因此在计算上比一次链接所有转换并在图像上只运行一次 gm 更昂贵。
    • @SBBS: 不,gm 无法区分是否赋值给变量,只要链同步执行即可。使用这种构建器模式,我很确定只有当您调用.toBuffer() 时才会发生工作。如果写得好,你可以同时调用两次.toBuffer(),它会运行两次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-01
    • 2015-05-29
    • 1970-01-01
    • 2023-03-07
    • 2017-09-11
    • 2018-10-30
    • 2023-02-09
    相关资源
    最近更新 更多