关于前端和后端的计算效率问题。 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
luo123qiu
V2EX    问与答

关于前端和后端的计算效率问题。

  •  
  •   luo123qiu 2014 年 12 月 2 日 7579 次点击
    这是一个创建于 4085 天前的主题,其中的信息可能已经有所发展或是发生改变。
    比较典型的需求

    前端AJAX向后端请求一组数据,其中包含了分页信息(总页数、item总数)。

    那么问题来了,这个计算总页数和item数量的工作,到底是交给后端计算好了直接返回给前端,还是前端来进行计算呢?哪种效率会更高?为什么?不同场景下呢?

    延伸:局部刷新的典型需求,是后端生成好html返回给前端直接插入,还是后端只返回数据
    前端来完成dom结构呢?

    注意:仅讨论问题本身,一些未提到的细节问题先忽略。

    PS:问这个问题,主要是最近和后端方面同学有一些矛盾。他认为“我是不是要把10000个人的压力 分担给10000个人呢,还是都放服务端呢”(原话),而我认为后端在计算方面可能比前端效率会更高一些。
    15 条回复    2014-12-02 22:58:29 +08:00
    Ghoul2005
        1
    Ghoul2005  
       2014 年 12 月 2 日   1
    1.从节约服务器资源的角度考虑,能放到客户端计算的逻辑,就不要用服务端去做。客户端多计算一次1+1是一件微不足道的事,但是一亿次1+1计算,放到服务器上去做可能就要额外多部署几台服务器,这都是成本。

    2.如果某些逻辑丢到客户端去做,会严重影响用户体验(例如导致浏览器卡死甚至整个系统卡死),那就得不偿失,用户体验第一。

    3.实际操作上还涉及到开发的分工问题,通常前台开发和后台开发是分开的,如果省下的服务器资源不多,但是却导致了分工混乱,也没必要这样做。
    exodia
        2
    exodia  
       2014 年 12 月 2 日   1
    个人观点:

    仅从计算资源成本角度来说,当然是客户端计算来的节约。

    效率问题:

    如果网站并发比较大,大到一个临界值 x 以上,前端计算比较能够保证稳定性,后端响应能力相对减弱;

    如果网站并发一般,在临界值 x 以下,后端渲染,生成 html 字符串给前端较快。如果要兼容 ie7这种不带原生 JSON 对象的浏览器,靠前端渲染 html 估计界面会挂。

    不过这个 x 很多时候都是一个经验值,而一般的网站选择前端渲染和后端渲染很大程度依赖于前后端的人力资源以及整体的架构。

    如果架构是 spa,那么基本是由前端来渲染的;如果是传统的 web page,由后端生成还是前端来搞取决于上面提到的临界值以及开发资源(前端多么,那就前端来搞,后端多么后端搞)。
    jiyinyiyong
        3
    jiyinyiyong  
       2014 年 12 月 2 日   1
    我们在 Teambition 后端会考虑性能比较多, 前端慢就慢了.
    因为前端有的是慢的地方, 特别是 DOM 操作的部分, 仅仅做这样一点改变提高不了多少.
    haxe
        4
    haxe  
       2014 年 12 月 2 日   1
    用户的硬件配置是没有底线的,而服务器的配置是可以预期的。所以涉及到计算效率的东西放在后端更让人睡得放心。
    loading
        5
    loading  
       2014 年 12 月 2 日 via Android   1
    提醒一下,请注意js的精度问题。
    imn1
        6
    imn1  
       2014 年 12 月 2 日   1
    即使是你那位后端同事的话,也要视情况而定的,你说的这个例子其实也要斟酌
    如果仅仅是算个数字,前端好
    但如果还要按计算结果二次请求数据,例如会产生二次ajax,最好再研究和商量

    一般论
    高频的简易计算,前端
    低频甚至半静态的,后端,例如有些产品数据是好久才更新一次的、查询方式也相对固定的,可以在后端利用cache
    复杂、需要精准或计算有一定保密性的数据,后端,例如证券、财务、需要隐藏算法的
    例如证券或某些图表数据也是高频、实时的,但这个是无法押宝在客户端的
    luo123qiu
        7
    luo123qiu  
    OP
       2014 年 12 月 2 日
    @Ghoul2005 那如果单从执行效率上来讲,遍历数据返回总数这个操作,后端执行返回和前端直接计算,哪个更有优势?
    @exodia
    @loading
    @imn1
    @jiyinyiyong
    @haxe

    感谢。
    learnshare
        8
    learnshare  
       2014 年 12 月 2 日   1
    计算一个分页数量的问题,还用纠结前端还是后端做?

    来分析一下这个问题:
    1. 数据总量(items)直接来自数据库;
    2. 每页数据量(pageItems)可以前端指定,也可以后端指定;
    3. 总页数(pages)= items / pageItems。

    怎么搞?
    1. 一次性将 items 全部丢给前端,前端根据 pageItems 分页展示(或者一个页面直接展示)
    这个方案不可行。
    2. 前端给后端提供 pageItems(如 10) 和指定页(page 如 3),后端把 21~30 项 item 返回
    3. 前端给后端提供指定页(page 如 3),后端预设 pageItems(如 10) ,后端把 21~30 项 item 返回

    后边两种方案都是推荐的方法。

    ----------
    你说的问题,应该是前端需要显示[数据总量]、[当前页码]和[总页数],这些值可以这么来:
    1. 后端提供 items (也可以包含 page,这个最好前后端都维护一个。当然,后端返回的那个是前端提供的)
    pages = items / pageItems
    2. 后端根据前端提供的 page 和 pageItems,直接计算 pages 并返回

    第一种方法更好一些。
    learnshare
        9
    learnshare  
       2014 年 12 月 2 日   1
    @luo123qiu 补充你这个问题

    >遍历数据返回总数这个操作,后端执行返回和前端直接计算,哪个更有优势?

    1. 如果你要知道数据库里的一张表的总数量,这个只能后端做;
    2. 如果你要知道后端操作返回集合的长度,这个后端速度快,但前端处理更好:

    比如你调用了一个搜索 API,想知道搜索到了多少条结果:
    后端程序执行完数据库的搜索动作,就可以知道查找到的结果数量。BUT,这个数量对你很有意义么?前端不是很容易 list.length 去到么,会有很大的性能问题?
    如果直接返回结果列表,JSON 结构可以是:
    [
    {item1},
    {item2},
    {item3},
    {...}
    ]

    如果给你附加一个 length 参数:
    {
    length: n,
    results:[
    {item1},
    {item2},
    {item3},
    {...}
    ]
    }

    可以来衡量一下有多少差别。
    akfish
        10
    akfish  
       2014 年 12 月 2 日   1
    这事显然是个trade-off的问题,比如:

    带宽贵还是计算贵?如果带宽贵,那么宁愿消耗服务器的计算资源,把压缩、简化、挖掘等操作放在服务器短跑,然后就只需要传输较少数据了。
    要安全还是要性能?比如游戏逻辑、交易之类的业务,显然就不能放客户端跑,硬着头皮都得服务器上撸。

    至于其他那些在哪端跑对于性能/安全影响都不大的情况,不过就是个convention而已。比如分页这种事,多算次除法还是少算次除法又能把性能怎样呢?DOM前端生成还是后端生成又有多大的本质区别呢?
    这种情况下,唯一需要注意的就是保持项目内的一致性。同类数据/逻辑,比如不能说一些地方服务器端跑,一些地方又客户端跑。

    我看lz举的这两个业务流程,在大多数情况下,跑哪端都不会对性能有多大的冲击,你确定你们不是为了argue而argue?
    otakustay
        11
    otakustay  
       2014 年 12 月 2 日   1
    控制网络上传输的量,计算交给前端更省,天生超级分布式……

    所以像分页这种,如果后端不分页就会导致所有数据传输,网络传输量大了,这就得不偿失了
    luo123qiu
        12
    luo123qiu  
    OP
       2014 年 12 月 2 日
    @learnshare 就是我让后端同学在返回items的时候,同时把length返回给我省得我再计算一次了,他怎么都不肯。。。然后我们就吵起来了。。。
    learnshare
        13
    learnshare  
       2014 年 12 月 2 日   1
    @luo123qiu lenth 最好前端计算,(没个百万条数据)完全不用考虑性能问题
    ozking
        14
    ozking  
       2014 年 12 月 2 日   1
    @luo123qiu 吵起来了,哈哈哈
    SoloCompany
        15
    SoloCompany  
       2014 年 12 月 2 日   1
    @luo123qiu 假如是一个很简单的分页,假设获得一次分页数据的开销是x,获得记录总是的开销是y,如果y完全可以忽略,那么你让后端每次请求都同时返回x和y是对的,这样你翻十页就需要10(x+y)的开销,如果y的计算和x相若,甚至超过x,那么你的同事是对的,他应该在一次独立的请求中返回y,然后你每次请求中只返回x,这样你翻十页需要的10x+y的开销,不用重复的去count,要知道有些数据库的count操作是很昂贵的,当然服务器也可以通过session等机制把y缓存下来,这样都增加了业务的复杂性,假如前端可以有状态,比如是单页面应用,都是通过json/ajax请求来获取数据,这样设计接口也很合理
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     855 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 21:24 PVG 05:24 LAX 13:24 JFK 16:24
    Do hve faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86