首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
Coding
V2EX  ›  JavaScript

看到一道面试题:<ul>有 10000 个<li>子元素,如何将这 10000 个<li>颠倒顺序。

  •  2
     
  •   mikej · 2014-02-19 22:58:16 +08:00 · 35420 次点击
    这是一个创建于 2123 天前的主题,其中的信息可能已经有所发展或是发生改变。
    要求是效率尽量要高。不光是算法效率,还要考虑DOM元素操作的效率。大家有什么想法?
    还有就是遇到类似这种问题解题技巧?
    104 回复  |  直到 2016-10-24 21:06:21 +08:00
    1  2  
        1
    democ   2014-02-19 23:13:59 +08:00   ♥ 1
    1. 先复制一份 (不要插入到DOM中,频繁的操作DOM消耗资源是很大的)
    2. 对复制出的这份做操作. 方法是从最后一个开始拿插入到一个新的<ul>中 (这一步也不需要插入到DOM中)
    3. 将DOM中的<ul>更换为从新排序的<ul>

    有不合适的地方请楼下指出.
        2
    learnshare   2014-02-19 23:29:08 +08:00
    在内存中操作完成,然后插入到页面中
        3
    kfll   2014-02-19 23:31:23 +08:00
    @democ 复制的实现复杂效率也不高,`cloneNode` 也不克隆事件
    @mikej 我的话会掐半用 `replaceChild` 首尾交换
    关系到 DOM 的优先考虑浏览器 API 再考虑算法..
    不一定对...
        4
    bombless   2014-02-19 23:34:35 +08:00
    先remove掉ul,首尾交换上面的li再把ul插回去
        5
    P233   2014-02-19 23:39:30 +08:00   ♥ 87
    ul {transform: rotate(180deg)}

    li {transform: rotate(180deg)}

    搞定
        6
    tinyhill   2014-02-19 23:45:38 +08:00   ♥ 1
    [].slice.call(nodeList).reverse(); 循环一次组成字符串插回 ul 节点
        7
    chairuosen   2014-02-19 23:46:07 +08:00 via Android
    卧槽,楼上机智!!
        8
    fakefish   2014-02-19 23:49:55 +08:00
    fragementElement+=(lastchild--)
    parent.append(fragementElement)
    大概是这么个意思,把从最后的一个子元素开始复制到fragmentElement,组装完再一起插入原处
        9
    fakefish   2014-02-19 23:53:22 +08:00
    速度最快的肯定不能让dom在每次循环的时候有变化。
        10
    blacktulip   2014-02-19 23:54:08 +08:00 via iPhone
    五楼正解
        11
    sneezry   2014-02-19 23:54:26 +08:00
    最快的方法我感觉是innerHTML
        12
    sneezry   2014-02-19 23:55:09 +08:00
    @P233 五楼你碉堡了。。。
        13
    Sunyanzi   2014-02-19 23:57:54 +08:00
    只有我觉得只要简单的遍历一遍然后生成一个反向的大字符串写入 innerHTML 就好吗 ...

    这样的优点是快 ... 生成字符串绝对比任何的 DOM 操作来得都要高效 ...

    缺点是重新生成了列表 ... 所有原来元素上面的事件和属性都没了 ...

    如果要保持原来的元素 ... 大概也只能二分之后 replaceChild 了吧 ...
        14
    clippit   2014-02-20 00:05:27 +08:00
    http://jsperf.com/reverse-li

    10000的时候确实用数组 reverse 比较快,但是如果 DOM 节点比较少的时候,反而是直接操作比较快呢
        15
    crs0910   2014-02-20 00:12:26 +08:00 via Android
    http://stackoverflow.com/questions/5530472/how-to-handle-10000-li-efficiently
    手机chrome测试,字符串和DOM操作响应差不多。
        16
    democ   2014-02-20 00:54:59 +08:00
    @clipplt 涨姿势了.数据说话.
        17
    alay9999   2014-02-20 02:23:37 +08:00
    五楼!五体投地!
        18
    jprovim   2014-02-20 03:20:25 +08:00
    @P233 非常好的Trick
        19
    FrankFang128   2014-02-20 09:08:29 +08:00 via Android
    这题哪看到的?
        20
    mikej   2014-02-20 09:10:30 +08:00
    @clippit 佩服,真会解决问题
    @P233 太颠覆了。。。
    @fakefish 不错啊,思路挺清晰,代码也很简练。
        21
    mikej   2014-02-20 09:12:45 +08:00
    @FrankFang128 知乎
        22
    laoona   2014-02-20 09:13:43 +08:00
    给五楼跪了!
        23
    FrankFang128   2014-02-20 09:32:35 +08:00 via Android
    @mikej 这个问题是我出的。。。我只是随口一说的,想不到有人转到V2了 :)
        24
    mengzhuo   2014-02-20 09:46:46 +08:00
    5楼太机智了!怒赞一个!
    以后的倒序直接加class就over了,js代码又省了很多
        25
    doublleft   2014-02-20 09:47:53 +08:00
    @P233 好机制!!!!!!
        26
    ccccccc   2014-02-20 10:02:48 +08:00
    可以用css3 flex order改变排序
        27
    geew   2014-02-20 10:41:18 +08:00
    5楼碉堡了, 10086个怒赞
        28
    paloalto   2014-02-20 10:48:57 +08:00
    5楼太颠覆了!!! !
        29
    RoshanWu   2014-02-20 10:51:45 +08:00
    我是来看5楼的,啊,真是个机智的骚年
        30
    avastms   2014-02-20 11:02:29 +08:00
    次奥怒赞5楼
        31
    shiye515   2014-02-20 11:03:12 +08:00
    @P233
        32
    learnshare   2014-02-20 11:07:06 +08:00
    五楼... 给跪了
        33
    January   2014-02-20 11:42:29 +08:00
    五楼笑死我了
        34
    atian25   2014-02-20 11:46:46 +08:00   ♥ 1
    赞5楼...
    还有个:
    <ol reversed>
    <li>list item one</li>
    <li>list item two</li>
    <li>list item three</li>
    <li>list item four</li>
    <li>list item five</li>
    </ol>
    http://www.w3schools.com/tags/att_ol_reversed.asp
        35
    mikej   2014-02-20 11:46:57 +08:00
    @FrankFang128 是吗?呵呵,没想到还能在这里遇到。。
        36
    iamjs   2014-02-20 12:02:41 +08:00
    5楼。。直接面试官崩溃的节奏。。
        37
    Sight4   2014-02-20 12:05:55 +08:00
    @P233 神回复!!
        38
    shiny   2014-02-20 12:12:13 +08:00
    5楼是嘲弄面试官呀
        39
    kevinroot   2014-02-20 12:23:50 +08:00
    @P233 碉堡~样式大神
        40
    honk   2014-02-20 12:42:59 +08:00
    @P233 不得不贊!!
        41
    refresh   2014-02-20 12:44:23 +08:00
    @P233 不是css3不支持吧
        42
    spheee   2014-02-20 13:31:02 +08:00
    @P233 太厉害了
        43
    jacob   2014-02-20 13:59:17 +08:00
    @P233 css对js强力逆袭啊。
        44
    Ellison   2014-02-20 14:41:55 +08:00
    5楼怒赞...
        45
    fim8   2014-02-20 14:48:55 +08:00
    热情的转到知乎。
        46
    unnya   2014-02-20 14:59:31 +08:00
    @P233 忍不住点个赞
        47
    aisensiy   2014-02-20 15:14:09 +08:00
    @sneezry 我觉得也是
        48
    P233   2014-02-20 16:11:50 +08:00
    @refresh IE9+ 都支持
        49
    P233   2014-02-20 16:11:59 +08:00
    感谢大家!
        50
    tonitech   2014-02-20 16:14:32 +08:00
    @P233 厉害厉害!!!哈哈哈!
        51
    shiniv   2014-02-20 19:09:09 +08:00
    怒赞
        52
    sanddudu   2014-02-20 19:48:03 +08:00
    @atian25 这个只颠倒序号。所以只支持有序列表,题目用的是无序的
        53
    zztczcx   2014-02-20 20:17:48 +08:00
    我是来看5楼的
        54
    princexu   2014-02-20 20:22:14 +08:00
    5楼碉堡了....
        55
    jieorlin   2014-02-20 20:24:06 +08:00
    ### fdsafdfdsf
        56
    jieorlin   2014-02-20 20:25:38 +08:00   ♥ 1
        58
    lichgo   2014-02-20 21:01:53 +08:00
    5楼的解法让我想到一道经典算法题:
    Reverse words in a sentence: "I am a geek" => "geek a am I"。

    另外,应用CSS在10000个DOM元素上,每个元素都要重画(repaint)吧?效率如何?会比JS更高?
        59
    lnehe   2014-02-20 21:06:08 +08:00
    把显示器倒过来。。。。
        60
    ericls   2014-02-20 21:55:32 +08:00
    5 楼碉堡了!
        61
    Artotria   2014-02-20 22:20:05 +08:00
    我是来围观5楼的,机智的骚年~
        62
    ccming   2014-02-20 22:20:16 +08:00
    好腻害
        63
    MingZhe   2014-02-20 22:36:48 +08:00
    由于不是搞前端的,对五楼的说法刚开始没注意。没想到下面这么多人赞,果断去查。。。确实碉堡了。给赞一个
        64
    iamjs   2014-02-20 22:43:30 +08:00
    @lichgo 难说 因为几乎不可能在真实的场景中遇到。典型的面试题目。
    如果我是面试官。给我一个js转换方法和这个答案。我想后者更能给考官留下深刻印象吧。。
        65
    FrankFang128   2014-02-20 23:06:41 +08:00
    @iamjs 大家喜欢抖机灵的答案
        66
    RIcter   2014-02-21 00:04:31 +08:00
    @FrankFang128 不过不失为一个好办法。
        67
    donkeylucky   2014-02-21 08:54:10 +08:00
    5楼的 大大的机智
        68
    andy12530   2014-02-21 09:00:52 +08:00
    如果不考虑普通低级浏览器,5楼的办法是最简单好用的。
        69
    qazwsxedc   2014-02-21 10:11:46 +08:00
    围观5楼
        70
    shiye515   2014-02-21 10:45:00 +08:00
    @lichgo js添加元素不也要重绘么,还要加上操作dom的时间
        71
    hilenlai   2014-02-21 11:05:33 +08:00
    5楼太机智了!!
        72
    siyang1982   2014-02-21 11:05:55 +08:00
    在本页玩了一下:`$('#Main .box:eq(1), #Main .box:eq(1) > *').css('transform', 'rotate(180deg)')`
        73
    fen   2014-02-21 11:46:52 +08:00
    @P233 5 楼无敌
        74
    YufunHe   2014-02-21 11:50:14 +08:00
    围观五楼
        75
    ffts   2014-02-21 12:40:58 +08:00
    卧槽,看了演示之后才知道5楼的想法多NB
        76
    lidonghao   2014-02-21 12:45:06 +08:00
    5楼的答案 面试官也不能说错啊 哈哈
        77
    airski   2014-02-21 13:10:32 +08:00
    大赞机智的5楼。
        78
    lijsh   2014-02-21 13:27:21 +08:00
        79
    HeyMan   2014-02-21 13:27:30 +08:00
    想象力真强!
        80
    flynngao   2014-02-21 13:52:46 +08:00
    5楼鸡汁超越人类
        81
    adam   2014-02-21 14:01:56 +08:00
    可以作为一条面试题~~
        82
    est   2014-02-21 14:03:49 +08:00
    @siyang1982 卧槽居然成功了
        83
    rekey   2014-02-21 15:18:30 +08:00
    特地赶来赞5楼的.
        84
    Keinez   2014-02-21 16:38:20 +08:00 via Android
    @P233 五楼已经颠覆我对CSS3的认知
        85
    zzNucker   2014-02-21 16:45:27 +08:00
    @lichgo CSS3动画是不需要repaint的。
        86
    FrankFang128   2014-02-21 19:02:20 +08:00 via Android
    @RIcter 充分说明前端思维角度和后台是不同的
        87
    sampeng   2014-02-21 20:51:34 +08:00
    由于我带前端团队。。
    这个题目,我刚看到。第一反应是,这是个好题。。第二反应,取出来。用算法,然后插入dom。这个是常规的。第三反应,css是控制显示的。如果用css控制呢?我不懂css。所以,我会先用个第二种方式上线,因为开发快。写代码,不一定要精细到极致,一切都是可改的。完全可以满足产品需求,回头再改(如果记得的话)。然后再找时候去网上找找css有没办法。。。收工。
    如果面试的用上面的这个思路来回答,我会直接弄进来。。赶紧去给我去干活
        88
    otakustay   2014-02-21 20:57:22 +08:00
    @zzNucker 你确定?不需要relayout/reflow我知道,repaint也不需要那屏幕上的东西是如何改变的?CSS3的translate3D顶多也就是让浏览器支持图层缓存,不用repaint感觉有点太厉害了啊
        89
    otakustay   2014-02-21 20:59:55 +08:00
    @lichgo 效率比JS高那是轻轻松松,JS这么做一是DOM结构变化的计算,二是函数调用的损耗(JS<->DOM不是一般的JS函数调用,往往要走一个代理或者序列化),三是引起重布局的损耗,四是有没有浏览器做GPU加速之类的优化的区别
        90
    zzNucker   2014-02-21 21:23:21 +08:00
    @otakustay 唔,我这样表达确实不太对,是不做传统意义上的那种非常耗资源的repaint,就是整个renderlayer tree的重绘。 而用CSS Translate3D这种的话,在开启了硬件合成加速以后会直接在GPU RAM里作为texture改变,就相当于改变的部分很少,而且基本不占用CPU资源。
        91
    zzNucker   2014-02-21 21:38:33 +08:00
    刚发现chrome新版取消了windows下的强制合成的选项。
        92
    zzNucker   2014-02-21 21:40:14 +08:00
    难道已经默认启用了。
        93
    P233   2014-02-21 23:10:34 +08:00
    @lichgo
    @shiye515
    @otakustay
    @zzNucker

    做了个简单的测试(可能并不严谨),Chrome 下 10000 个 li 元素,page paint time 在 3.4ms - 4.7ms 左右;使用 ul,li {transform: rotate(180deg)} 反转后(不会开启 GPU 加速),骤增到 13.2ms - 16.6ms 左右;translateZ(0) 强制开启 GPU 加速后,page paint time 只有 1.5ms - 1.8ms
        94
    otakustay   2014-02-22 00:05:42 +08:00
    @P233 感谢实验,理论上translateZ因为有贴图缓存支持肯定够快,DOM操作可能会因为li中的内容复杂度有很大的区别,而transform我理解应该和内容复杂度关系不呈线性
        95
    mikej   2014-02-22 00:17:54 +08:00
    @otakustay
    @zzNucker
    @P233
    研究得够深!都是前端牛人啊。
        96
    lygmqkl   2014-02-22 01:11:41 +08:00
    做了6年后端了,说实话 五楼的想法让我眼前一亮,web 不只是数据。 哈哈
        97
    P233   2014-02-22 07:03:26 +08:00
    @otakustay 应该是这样的,贴两张测试截图





    开启 GPU 加速后,recalculate 时间竟然增加了很多,但 paint time 毫无疑问减少了
        98
    iLluSioN   2014-02-22 10:24:08 +08:00
    ……给五楼跪
        99
    jabbany   2014-02-23 05:39:30 +08:00
    太机智了.......
        100
    sobigfish   2014-02-26 20:02:44 +08:00
    @siyang1982 也是直接论坛最近回复在前的解决方法
    1  2  
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1050 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 30ms · UTC 23:20 · PVG 07:20 · LAX 15:20 · JFK 18:20
    ♥ Do have faith in what you're doing.