Your SlideShare is downloading. ×
0
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
D2_Node在淘宝的应用实践
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

D2_Node在淘宝的应用实践

2,207

Published on

Published in: Technology
0 Comments
23 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,207
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
105
Comments
0
Likes
23
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Transcript

    1. Node在淘宝的应用实践这些年,我们一起 发过的Node.jsBy @朴 1
    2. 于我2
    3. 于我• CNode社区 2
    4. 于我• CNode社区• 前端 at SAP for Mobile Web 2
    5. 于我• CNode社区• 前端 at SAP for Mobile Web• 前端 at 淘宝数据产品部 2
    6. 于我 连• CNode社区 IE6都能兼容的• 前端 at SAP for Mobile Web• 前端 at 淘宝数据产品部 2
    7. 议程 3
    8. 议程• 我为什么要做Node 发 3
    9. 议程• 我为什么要做Node 发• 准备工作与作品 3
    10. 议程• 我为什么要做Node 发• 准备工作与作品• Node.js带来的新问题与如何逆袭 • 步编程 • 缓存与内存 • Buffer 3
    11. 议程• 我为什么要做Node 发• 准备工作与作品• Node.js带来的新问题与如何逆袭 • 步编程 • 缓存与内存 • Buffer• Node.js在淘宝产品中的一点实践 3
    12. 长达半天的欢乐 4
    13. 长达半天的欢乐 4
    14. 长达半天的欢乐 4
    15. 长达半天的欢乐 4
    16. 长达半天的欢乐 4
    17. 长达半天的欢乐前端屌丝的坎 路 4
    18. 长达半天的欢乐 icons powered by morcha design前端屌丝的坎 路 4
    19. Node与前端的亲缘 5
    20. Node与前端的亲缘 6
    21. Node与前端的亲缘 6
    22. Node与前端的亲缘 6
    23. 左手HTML5右手Node.js 7
    24. 左手HTML5右手Node.js• 熟知的JavaScript执行原理/事件循环 7
    25. 左手HTML5右手Node.js• 熟知的JavaScript执行原理/事件循环• 熟悉的API、事件、单线程、回调 7
    26. 左手HTML5右手Node.js• 熟知的JavaScript执行原理/事件循环• 熟悉的API、事件、单线程、回调• Ajax/ 步 7
    27. 左手HTML5右手Node.js• 熟知的JavaScript执行原理/事件循环• 熟悉的API、事件、单线程、回调• Ajax/ 步• 相比HTML5,Node将 启更多的可能性 7
    28. 好奇心 & 满足感 8
    29. 好奇心 & 满足感• HTTP协议栈:深入后端,反哺前端 8
    30. 好奇心 & 满足感• HTTP协议栈:深入后端,反哺前端• Status code 8
    31. 好奇心 & 满足感• HTTP协议栈:深入后端,反哺前端• Status code• Cookie & Session 8
    32. 好奇心 & 满足感• HTTP协议栈:深入后端,反哺前端• Status code• Cookie & Session• Request & Response 8
    33. 好奇心 & 满足感• HTTP协议栈:深入后端,反哺前端• Status code• Cookie & Session• Request & Response• Web Framework 8
    34. 好奇心 & 满足感• HTTP协议栈:深入后端,反哺前端 • Status code • Cookie & Session • Request & Response • Web Framework• 高性能JavaScript平台 8
    35. 好奇心 & 满足感• HTTP协议栈:深入后端,反哺前端 • Status code • Cookie & Session • Request & Response • Web Framework• 高性能JavaScript平台• 拓宽视野 8
    36. Go, go, go!!! 9
    37. Go, go, go!!! 9
    38. Go, go, go!!! 9
    39. Go, go, go!!!var http = require(http);http.createServer(function (req, res) { res.writeHead(200, {Content-Type: text/plain}); res.end(Hello Worldn);}).listen(1337, 127.0.0.1);console.log(Server running at http://127.0.0.1:1337/); 9
    40. Go, go, go!!! 9
    41. Go, go, go!!!% node example.jsServer running at http://127.0.0.1:1337/ 9
    42. 作品 10
    43. 作品 10
    44. 作品 10
    45. 全JavaScript堆栈的产品 11
    46. 全JavaScript堆栈的产品 11
    47. 全JavaScript堆栈的产品 11
    48. 全JavaScript堆栈的产品 11
    49. 全JavaScript堆栈的产品 Connect 11
    50. 全JavaScript堆栈的产品 Connect 11
    51. 全JavaScript堆栈的产品 ConnectRedis & MRedis 11
    52. 全JavaScript堆栈的产品 ConnectRedis & MRedis 11
    53. 全JavaScript堆栈的产品 ConnectRedis & MRedis MongoSkin 11
    54. 全JavaScript堆栈的产品 Connect ITierRedis & MRedis MongoSkin 11
    55. 全JavaScript堆栈的产品 Connect ITierRedis & MRedis MongoSkin 11
    56. 全JavaScript堆栈的产品 Connect ITierRedis & MRedis MongoSkin Should 11
    57. 全JavaScript堆栈的产品 Connect ITierRedis & MRedis MongoSkin Should 11
    58. 全JavaScript堆栈的产品 ConnectWebGhost ITierRedis & MRedis MongoSkin Should 11
    59. 前端工程师到Web工程师 12
    60. 前端工程师到Web工程师如何摆脱前端屌丝的身份 12
    61. 前端工程师到Web工程师 让女神青睐如何摆脱前端屌丝的身份 12
    62. 前端工程师到Web工程师 让女神青睐如何摆脱前端屌丝的身份 结果重了10斤 12
    63. 前端工程师到Web工程师 让女神青睐 结果重了10斤 12
    64. 问题: 步协作• 嵌套还是并行? 13
    65. 问题: 步协作• 嵌套还是并行?$.get("template", function (template) { // something $.get("data", function (data) { // something $.get("l10n", function (l10n) { // something render(template, data); }); });}); 13
    66. 问题: 步协作• 嵌套还是并行? 13
    67. 问题:var proxy = new EventProxy(); 步协作•proxy.all("template", "data", "l10n", render); 嵌套还是并行?$.get("template", function (template) { // something proxy.trigger("template", template);});$.get("data", function (data) { // something proxy.trigger("data", data);});$.get("l10n", function (l10n) { // something proxy.trigger("l10n", l10n);}); 13
    68. 问题: 步还是同步• 杂的 步编程 14
    69. 问题: 步还是同步var proxy = new EventProxy();var status = "ready";• 杂的 步编程var _getFile = function (callback) { proxy.once("template", callback); if (status === "ready") { fs.readFile("views/index.html", function (err, file) { status = "pending"; proxy.fire("template", err, file); }); }};var _template;var getTemplate = function (callback) { if (_template) { callback(null, _template); } else { _getFile(function (err, file) { if (!err && !_template) { _template = file.toString(); } callback(null, _template); }); }}; 14
    70. 问题: 步还是同步• 杂的 步编程 14
    71. 问题: 步还是同步• 杂的 步编程var view = fs.readFileSync("../views/index.html", "utf8"); 14
    72. 问题: 步还是同步• 杂的 步编程var view = fs.readFileSync("../views/index.html", "utf8");同步 + 缓存,妥妥滴 14
    73. 问题:缓存的使用 15
    74. 问题:缓存的使用var map = {};var get = function (key) { return map[key];};var set = function (key, value) { map[key] = value;};// 检查缓存if (!get(key)) { // 从数据库或 的地方获取了对象后,放进缓存中 set(key, value); 15
    75. 问题:缓存的使用 15
    76. 问题:缓存的使用var LimitableMap = require(limitablemap);var map = new LimitableMap(1000);map.set("key1", "key1");map.get("key1"); 15
    77. 问题:Session 16
    78. 问题:Session• V8内存堆栈限制 16
    79. 问题:Session• V8内存堆栈限制• 分布式中,Session需要共享(Redis) 16
    80. 问题:Session• V8内存堆栈限制• 分布式中,Session需要共享(Redis)• 重启应用不丢失session 16
    81. 问题:Session• V8内存堆栈限制• 分布式中,Session需要共享(Redis)• 重启应用不丢失session• 多点Redis,备份容灾 16
    82. 问题:Buffer对象 17
    83. 问题:Buffer对象var data = "";res.on(data, function (chunk) { // chunk是一个Buffer对象 data += chunk;// 隐藏的toString()}).on("end", function () { //对data转码}); 17
    84. 问题:Buffer对象 17
    85. // 正 的方法var chunks = [];var size = 0; 问题:Buffer对象res.on(data, function (chunk) { chunks.push(chunk); size += chunk.length;});res.on(end, function () { var data = null; switch(chunks.length) { case 0: data = new Buffer(0); break; case 1: data = chunks[0]; break; default: data = new Buffer(size); for (var i = 0, pos = 0, l = chunks.length; i < l; i++) { var chunk = chunks[i]; chunk.copy(data, pos); pos += chunk.length; } break; } 17});
    86. 问题:Buffer对象 17
    87. 问题:Buffer对象// 简单且正 的方法var bufferHelper = new BufferHelper();req.on("data", function (chunk) { bufferHelper.concat(chunk);}).on(end, function () { var html = bufferHelper.toBuffer().toString();}); 17
    88. 问题:String传输的性能 18
    89. 问题:String传输的性能• 7k大小的静态文件,需做替换 18
    90. 问题:String传输的性能• 7k大小的静态文件,需做替换• String ➛ Buffer 18
    91. 问题:String传输的性能• 7k大小的静态文件,需做替换• String ➛ Buffer• 缓存Buffer,4倍性能提升 18
    92. 问题:多核CPU的利用 19
    93. 问题:多核CPU的利用• 单线程与多核CPU 19
    94. 问题:多核CPU的利用• 单线程与多核CPU• 单线程因为 常退出? 19
    95. 问题:多核CPU的利用• 单线程与多核CPU• 单线程因为 常退出?• 仿若熟悉的Web Worker: child_process 19
    96. 问题:多核CPU的利用• 单线程与多核CPU• 单线程因为 常退出?• 仿若熟悉的Web Worker: child_process• 进程与消息 19
    97. 问题:多核CPU的利用var cluster = require(node-cluster); •var master = new cluster.Master(); 单线程与多核CPUmaster.register(8080, app.js);master.dispatch(); • 单线程因为 常退出? • 仿若熟悉的Web Worker: child_process • 进程与消息 19
    98. 问题:多核CPU的利用var cluster = require(node-cluster); •var master = new cluster.Master(); 单线程与多核CPUmaster.register(8080, app.js);master.dispatch(); • 单线程因为 常退出?var http = require(http); • 仿若熟悉的Web Worker:var cluster = require(node-cluster); child_process • server = http.createServer(function (req, res) {var worker = new cluster.Worker();var 进程与消息 // server});worker.ready(function (socket) { server.emit(connection, socket);}); 19
    99. 问题:多核CPU的利用var cluster = require(node-cluster); •var master = new cluster.Master(); 单线程与多核CPUmaster.register(8080, app.js);master.dispatch(); • 单线程因为 常退出? 负载均衡var http = require(http); 多核利用 • 仿若熟悉的Web Worker:var cluster = require(node-cluster); child_process • server = http.createServer(function (req, res) {var worker = new cluster.Worker();var 进程与消息 // server});worker.ready(function (socket) { server.emit(connection, socket);}); 19
    100. 小结 20
    101. 小结• 步编程问题?EventProxy、JScex等 20
    102. 小结• 步编程问题?EventProxy、JScex等• 内存限制问题?第三方存储Redis 20
    103. 小结• 步编程问题?EventProxy、JScex等• 内存限制问题?第三方存储Redis• CPU消耗问题?缓存中间结果 20
    104. 小结• 步编程问题?EventProxy、JScex等• 内存限制问题?第三方存储Redis• CPU消耗问题?缓存中间结果• 单线程CPU利用不足问题?多进程 20
    105. 小结• 步编程问题?EventProxy、JScex等• 内存限制问题?第三方存储Redis• CPU消耗问题?缓存中间结果• 单线程CPU利用不足问题?多进程• 单线程稳定性问题?Node-Cluster 20
    106. 实践:运维 21
    107. 实践:运维• 常 21
    108. 实践:运维• 常• 日志 21
    109. 实践:运维• 常 // 步方法中try catch是不靠谱滴• 日志 // 步方法的 常 async(function (err, data) { if (err) { logger.error(err); return; // TODO } // TODO 21
    110. 实践:运维• 常• 日志 21
    111. 实践:运维• 常• 日志• 监控 21
    112. 实践:运维• 常• 日志 进程数量 CPU 内存• 监控 Load 磁盘IO 21
    113. 实践:运维• 常• 日志• 监控 21
    114. 实践:运维• 常• 日志• 监控• 部署 21
    115. 实践:运维• 常• 日志• 监控• 部署• 备份容灾 21
    116. 实践:运维• 常• 日志 双机房 双Redis MRedis模块• 监控 双MongoDB MongoSkin• 部署• 备份容灾 21
    117. 实践:运维• 常• 日志• 监控• 部署• 备份容灾 21
    118. 实践:测试 22
    119. 实践:测试• 测试 22
    120. 实践:测试• 测试• 单元测试 22
    121. 实践:测试• 测试• 单元测试 22
    122. 实践:测试• 测试• 单元测试 Should.js 22
    123. 实践:测试• 测试• 单元测试• 自动化测试 Should.js 22
    124. 实践:测试• 测试• 单元测试• 自动化测试 Should.js WebGhost 22
    125. 实践:测试• 测试• 单元测试• 自动化测试 Should.js• 性能测试 WebGhost 22
    126. 实践:测试• 测试• 单元测试• 自动化测试 Should.js• 性能测试 WebGhost 22
    127. 实践:测试• 测试• 单元测试• 自动化测试 Should.js• 性能测试 WebGhost• 持续集成 22
    128. 实践:CommonJS & Node & NPM 23
    129. 实践:CommonJS & Node & NPMCommonJS 23
    130. 实践:CommonJS & Node & NPMCommonJS 23
    131. 实践:CommonJS & Node & NPMCommonJS 23
    132. 实践:CommonJS & Node & NPMCommonJS 23
    133. 实践:CommonJS & Node & NPMCommonJS Node 23
    134. 实践:CommonJS & Node & NPMCommonJS Node 23
    135. 实践:CommonJS & Node & NPMCommonJS NPM Node 23
    136. 实践:CommonJS & Node & NPMCommonJS NPM Node 23
    137. 实践:公司范围内共享代码 24
    138. 实践:公司范围内共享代码• 如何保护隐私代码 24
    139. 实践:公司范围内共享代码• 如何保护隐私代码• 如何重用散乱代码 24
    140. 实践:公司范围内共享代码• 如何保护隐私代码• 如何重用散乱代码• 如何告 制粘贴 24
    141. 实践:公司范围内共享代码 25
    142. 实践:公司范围内共享代码 官方NPM 25
    143. 实践:公司范围内共享代码 官方NPM 25
    144. 实践:公司范围内共享代码 单向同步 官方NPM 25
    145. 实践:公司范围内共享代码 单向同步本地NPM 官方NPM 25
    146. 实践:公司范围内共享代码 单向同步本地NPM 官方NPM 25
    147. 实践:公司范围内共享代码 单向同步本地NPM 官方NPM 项目 25
    148. 实践:公司范围内共享代码 单向同步本地NPM 官方NPM 项目 25
    149. 实践:公司范围内共享代码 单向同步 本地NPM 官方NPM私有模块 项目 25
    150. 实践:公司范围内共享代码 单向同步 本地NPM 官方NPM私有模块 项目 25
    151. 实践:公司范围内共享代码 单向同步 本地NPM 官方NPM私有模块 项目 25
    152. 实践:公司范围内共享代码 单向同步 本地NPM 官方NPM私有模块 项目 公有模块 25
    153. 实践:公司范围内共享代码 单向同步 本地NPM 官方NPM私有模块 项目 公有模块 25
    154. 展望 26
    155. 展望• 深度发掘前端 发和用户体验 26
    156. 展望• 深度发掘前端 发和用户体验• 无需与 发沟通,节省成本 26
    157. 展望• 深度发掘前端 发和用户体验• 无需与 发沟通,节省成本• 知晓细节,更易改进产品体验 26
    158. 展望• 深度发掘前端 发和用户体验• 无需与 发沟通,节省成本• 知晓细节,更易改进产品体验• 感谢伟大的github 26
    159. 展望• 深度发掘前端 发和用户体验• 无需与 发沟通,节省成本• 知晓细节,更易改进产品体验• 感谢伟大的github• 感谢伟大的NPM促成的生态圈 26
    160. 展望• 深度发掘前端 发和用户体验• 无需与 发沟通,节省成本• 知晓细节,更易改进产品体验• 感谢伟大的github• 感谢伟大的NPM促成的生态圈• 感谢Node这件美妙的礼物 26
    161. Q&A 屌丝のぎゃくしゅう 27

    ×