120行代码实现 浏览器WebRTC视频聊天

本例子是参考webrtc-tutorial-simple-video-chat做的。 这个教程应该主要是去宣传ScaleDrone的sdk, 他们的服务是收费的,但是免费的也可以用,就是有些次数限制。 本栗子的地址 本栗子的pages地址 因为使用的是ScaleDrone的js sdk, 后期很可能服务不稳定之类的 1. 准备 使用最新版谷歌浏览器(62版) 视频聊天中 一个是windows, 一个是mac stun服务器使用谷歌的,trun使用ScaleDrone的sdk,这样我就不用管服务端了。 2. 先上效果图 3. 再上在线例子点击此处 4. 源码分析 // 产生随机数 if (!location.hash) { location.hash = Math.floor(Math.random() * 0xFFFFFF).toString(16); } // 获取房间号 var roomHash = location.hash.substring(1); // 放置你自己的频道id, 这是我注册了ScaleDrone 官网后,创建的channel // 你也可以自己创建 var drone = new ScaleDrone('87fYv4ncOoa0Cjne'); // 房间名必须以 'observable-'开头 var roomName = 'observable-' + roomHash; var configuration = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' // 使用谷歌的stun服务 }] }; var room; var pc; function onSuccess() {} function onError(error) { console....

2018-02-09 12:56:12 · 2 min · Eddie Wang

如何写好技术文档?

本文来自于公司内部的一个分享。 在文档方面,对内的一些接口文档主要是用swagger来写的。虽然可以在线测试,比较方便。但是也存在着一些更新不及时,swgger文档无法导出成文件的问题。 在对外提供的文档方面:我主要负责做一个浏览器端的一个js sdk。文档还算可以github地址,所以想把一些写文档的心得分享给大家。 1. 衡量好文档的唯一标准是什么? Martin(Bob大叔)曾在《代码整洁之道》一书打趣地说:当你的代码在做 Code Review 时,审查者要是愤怒地吼道: “What the fuck is this shit?” “Dude, What the fuck!” 等言辞激烈的词语时,那说明你写的代码是 Bad Code,如果审查者只是漫不经心的吐出几个 “What the fuck?”, 那说明你写的是 Good Code。衡量代码质量的唯一标准就是每分钟骂出“WTF” 的频率。 衡量文档的标准也是如此。 2. 好文档的特点 简洁:一句话可以说完的事情,就不要分两句话来说。并不是文档越厚越好,太厚的文档大多没人看。 准确: 字段类型,默认值,备注,是否必填等属性说明。 逻辑性: 文档如何划分? 利于查看。 demo胜千言: 好的demo胜过各种字段说明,可以复制下来直接使用。 读者心: 从读者的角度考虑, 方法尽量简洁。可以传递一个参数搞定的事情,绝对不要让用户去传两个参数。 及时更新: 不更新的文档比bug更严重。 向后兼容: 不要随意废弃已有的接口或者某个字段,除非你考虑到这样做的后果。 建立文档词汇表:每个概念只有一个名字,不要随意起名字,名不正则言不顺。 格式统一:例如时间格式。我曾见过2017-09-12 09:32:23, 或2017.09.12 09:32:23或2017.09.12 09:32:23。变量名user_name, userName。 使用专业词语:不要过于口语化 3. 总结: 写出好文档要有以下四点 逻辑性:便于查找 专业性: 值得信赖,质量保证 责任心:及时更新,准确性,向后兼容 读者心:你了解的东西,别人可能并不清楚。从读者的角度去考虑,他们需要什么,而不是一味去强调你能提供什么。 4. 写文档的工具 markdown: 方便快捷,可以导出各种格式的文件 swagger: 功能强大,需要部署,不方便传递文件 5....

2018-02-09 12:52:57 · 1 min · Eddie Wang

哑代理 - TCP链接高Recv-Q,内存泄露的罪魁祸首

1. 问题现象 使用netstat -ntp命令时发现,Recv-Q 1692012 异常偏高(正常情况下,该值应该是0),导致应用占用过多的内存。 tcp 1692012 0 172.17.72.4:48444 10.254.149.149:58080 ESTABLISHED 27/node 问题原因:代理的转发时,没有删除逐跳首部 2. 什么是Hop-by-hop 逐跳首部? http首部可以分为两种 端到端首部 End-to-end: 端到端首部代理在转发时必须携带的 逐跳首部 Hop-by-hop: 逐跳首部只对单次转发有效,代理在转发时,必须删除这些首部 逐跳首部有以下几个, 这些首部在代理进行转发前必须删除 Connetion Keep-Alive Proxy-Authenticate Proxy-Authortization Trailer TE Transfer-Encodeing Upgrade 3. 什么是哑代理? 很多老的或简单的代理都是盲中继(blind relay),它们只是将字节从一个连接转发到另一个连接中去,不对Connection首部进行特殊的处理。 (1)在图4-15a中 Web客户端向代理发送了一条报文,其中包含了Connection:Keep-Alive首部,如果可能的话请求建立一条keep-alive连接。客户端等待响应,以确定对方是否认可它对keep-alive信道的请求。 (2) 哑代理收到了这条HTTP请求,但它并不理解 Connection首部(只是将其作为一个扩展首部对待)。代理不知道keep-alive是什么意思,因此只是沿着转发链路将报文一字不漏地发送给服务器(图4-15b)。但Connection首部是个逐跳首部,只适用于单条传输链路,不应该沿着传输链路向下传输。接下来,就要发生一些很糟糕的事情了。 (3) 在图4-15b中,经过中继的HTTP请求抵达了Web服务器。当Web服务器收到经过代理转发的Connection: Keep-Alive首部时,会误以为代理(对服务器来说,这个代理看起来就和所有其他客户端一样)希望进行keep-alive对话!对Web服务器来说这没什么问题——它同意进行keep-alive对话,并在图4-15c中回送了一个Connection: Keep-Alive响应首部。所以,此时W eb服务器认为它在与代理进行keep-alive对话,会遵循keep-alive的规则。但代理却对keep-alive一无所知。不妙。 (4) 在图4-15d中,哑代理将Web服务器的响应报文回送给客户端,并将来自Web服务器的Connection: Keep-Alive首部一起传送过去。客户端看到这个首部,就会认为代理同意进行keep-alive对话。所以,此时客户端和服务器都认为它们在进行keep-alive对话,但与它们进行对话的代理却对keep-alive一无所知。 (5) 由于代理对keep-alive一无所知,所以会将收到的所有数据都回送给客户端,然后等待源端服务器关闭连接。但源端服务器会认为代理已经显式地请求它将连接保持在打开状态了,所以不会去关闭连接。这样,代理就会挂在那里等待连接的关闭。 (6) 客户端在图4-15d中收到了回送的响应报文时,会立即转向下一条请求,在keep-alive连接上向代理发送另一条请求(参见图4-15e)。而代理并不认为同一条连接上会有其他请求到来,请求被忽略,浏览器就在这里转圈,不会有任何进展了。 (7) 这种错误的通信方式会使浏览器一直处于挂起状态,直到客户端或服务器将连接超时,并将其关闭为止。 –《HTTP权威指南》 这是HTTP权威指南中,关于HTTP哑代理的描述。这里这里说了哑代理会造成的一个问题。 这种错误的通信方式会使浏览器一直处于挂起状态,直到客户端或服务器将连接超时,并将其关闭为止。 实际上,我认为哑代理还是造成以下问题的原因 TCP链接高Recv-Q tcp链接不断开,导致服务器内存过高,内存泄露 节点iowait高 在我们自己的代理的代码中,我有发现,在代理进行转发时,只删除了headers.host, 并没有删除headers.Connection等逐跳首部的字段 delete req.headers.host var option = { url: url, headers: req....

2018-02-08 21:58:31 · 1 min · Eddie Wang

定时器学习:利用定时器分解耗时任务案例

对于执行时间过长的脚本,有的浏览器会弹出警告,说页面无响应。有的浏览器会直接终止脚本。总而言之,浏览器不希望某一个代码块长时间处于运行状态,因为js是单线程的。一个代码块长时间运行,将会导致其他任何任务都必须等待。从用户体验上来说,很有可能发生页面渲染卡顿或者点击事件无响应的状态。 如果一段脚本的运行时间超过5秒,有些浏览器(比如Firefox和Opera)将弹出一个对话框警告用户该脚本“无法响应”。而其他浏览器,比如iPhone上的浏览器,将默认终止运行时间超过5秒钟的脚本。–《JavaScript忍者秘籍》 JavaScript忍者秘籍里有个很好的比喻:页面上发生的各种事情就好像一群人在讨论事情,如果有个人一直在说个不停,其他人肯定不乐意。我们希望有个裁判,定时的切换其他人来说话。 Js利用定时器来分解任务,关键点有两个。 按什么维度去分解任务 任务的现场保存与现场恢复 1. 例子 要求:动态创建一个表格,一共10000行,每行10个单元格 1.1. 一次性创建 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <table> <tbody></tbody> </table> <script type="text/javascript"> var tbody = document.getElementsByTagName('tbody')[0]; var allLines = 10000; // 每次渲染的行数 console.time('wd'); for(var i=0; i<allLines; i++){ var tr = document.createElement('tr'); for(var j=0; j<10; j++){ var td = document.createElement('td'); td.appendChild(document.createTextNode(i+','+j)); tr.appendChild(td); } tbody.appendChild(tr); } console.timeEnd('wd'); </script> </body> </html> 总共耗时180ms, 浏览器已经给出警告![Violation] 'setTimeout' handler took 53ms。 1.2. 分批次动态创建 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <table> <tbody></tbody> </table> <script type="text/javascript"> var tbody = document....

2018-02-08 14:09:54 · 1 min · Eddie Wang

关于JavaScropt函数式编程,我多么希望能早点看到这本书

我父亲以前跟我说过,有些事物在你得到之前是无足轻重的,得到之后就不可或缺了。微波炉是这样,智能手机是这样,互联网也是这样——老人们在没有互联网的时候过得也很充实。对我来说,函数的柯里化(curry)也是这样。 然后我继续看了这本书的中文版。有些醍醐灌顶的感觉。 随之在github搜了一下。 我想,即使付费,我也愿意看。 中文版地址:https://www.gitbook.com/book/llh911001/mostly-adequate-guide-chinese/details github原文地址:https://github.com/MostlyAdequate/mostly-adequate-guide 1. 后记 其实我是想学点函数柯里化的东西,然后用谷歌搜索了一下。第一个结果就是这本书。非常感谢谷歌搜索,如果我用百度,可能就没有缘分遇到这本书了。

2018-02-08 14:06:22 · 1 min · Eddie Wang

终于找到你!如何将前端console.log的日志保存成文件?

本篇文章来自一个需求,前端websocket会收到各种消息,但是调试的时候,我希望把websoekt推送过来的消息都保存到一个文件里,如果出问题的时候,我可以把这些消息的日志文件提交给后端开发区分析错误。但是在浏览器里,js一般是不能写文件的。鼠标另存为的方法也是不太好,因为会保存所有的console.log的输出。于是,终于找到这个debugout.js。 debugout.js的原理是将所有日志序列化后,保存到一个变量里。当然这个变量不会无限大,因为默认的最大日志限制是2500行,这个是可配置的。另外,debugout.js也支持在localStorage里存储日志的。 1. debugout.js 一般来说,可以使用打开console面板,然后右键save,是可以将console.log输出的信息另存为log文件的。但是这就把所有的日志都包含进来了,如何只保存我想要的日志呢? (调试输出)从您的日志中生成可以搜索,时间戳,下载等的文本文件。 参见下面的一些例子。 Debugout的log()接受任何类型的对象,包括函数。 Debugout不是一个猴子补丁,而是一个单独的记录类,你使用而不是控制台。 调试的一些亮点: 在运行时或任何时间获取整个日志或尾部 搜索并切片日志 更好地了解可选时间戳的使用模式 在一个地方切换实时日志记录(console.log) 可选地将输出存储在window.localStorage中,并在每个会话中持续添加到同一个日志 可选地,将日志上限为X个最新行以限制内存消耗 下图是使用downloadLog方法下载的日志文件。 官方提供的demo示例,欢迎试玩。http://inorganik.github.io/debugout.js/ 2. 使用 在脚本顶部的全局命名空间中创建一个新的调试对象,并使用debugout的日志方法替换所有控制台日志方法: var bugout = new debugout(); // instead of console.log('some object or string') bugout.log('some object or string'); 3. API log() -像console.log(), 但是会自动存储 getLog() - 返回所有日志 tail(numLines) - 返回尾部执行行日志,默认100行 search(string) - 搜索日志 getSlice(start, numLines) - 日志切割 downloadLog() - 下载日志 clear() - 清空日志 determineType() - 一个更细粒度的typeof为您提供方便 4. 可选配置 ··· // log in real time (forwards to console....

2018-02-08 13:56:40 · 1 min · Eddie Wang

如何浏览器里调试iframe里层的代码?

之前一直非常痛苦,在iframe外层根本获取不了里面的信息,后来使用了postMessage用传递消息来实现,但是用起来还是非常不方便。 其实浏览器本身是可以选择不同的iframe的执行环境的。例如有个变量是在iframe里面定义的,你只需要切换到这个iframe的执行环境,你就可以随意操作这个环境的任何变量了。 这个小技巧,对于调试非常有用,但是我直到今天才发现。 1. Chrome 这个小箭头可以让你选择不同的iframe的执行环境,可以切换到你的iframe环境里。 2. IE 如图所示是ie11的dev tool点击下来箭头,也可以选择不同的iframe执行环境。 3. 其他浏览器 其他浏览器可以自行摸索一下。。。(G_H)

2018-02-08 13:53:48 · 1 min · Eddie Wang

Audio 如果你愿意一层一层剥开我的心

我觉得DOM就好像是元素周期表里的元素,JS就好像是实验器材,通过各种化学反应,产生各种魔术。 1. Audio 通过打开谷歌浏览器的dev tools -> Settings -> Elements -> Show user agent shadow DOM, 你可以看到其实Audio标签也是由常用的 input标签和div等标签合成的。 2. 基本用法 1 <audio src="http://65.ierge.cn/12/186/372266.mp3"> Your browser does not support the audio element. </audio> <br> 2 <audio src="http://65.ierge.cn/12/186/372266.mp3" controls="controls"> Your browser does not support the audio element. </audio> <br> // controlsList属性目前只支持 chrome 58+ 3 <audio src="http://65.ierge.cn/12/186/372266.mp3" controls="controls" controlsList="nodownload"> Your browser does not support the audio element. </audio> <br> 4 <audio controls="controls"> <source src="http://65....

2018-02-08 09:44:01 · 2 min · Eddie Wang

可能被遗漏的https与http的知识点

1. HTTPS域向HTTP域发送请求会被浏览器直接拒绝,HTTP向HTTPS则不会 例如在github pages页面,这是一个https页面,如果在这个页面向http发送请求,那么会直接被浏览器拒绝,并在控制台输出下面的报错信息。 jquery-1.11.3.min.js:5 Mixed Content: The page at 'https://wangduanduan.github.io/ddddddd/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://cccccc/log/conf?token=welljoint'. This request has been blocked; the content must be served over HTTPS. 如果你在做第三方集成的系统,如果他们是在浏览器中直接调用你提供的接口,那么最好你使用https协议,这样无论对方是https还是http都可以访问。(相信我,这个很重要,我曾经经历过上线后遇到这个问题,然后连夜申请证书,把http升级到https的痛苦经历) 2. HTTPS的默认端口是443,而不是443 如果443端口已经被其他服务占用了,那么使用其他任何没有被占用的端口都可以用作HTTPS服务,只不过在请求的时候需要加上端口号罢了。 3. 如何快速隐藏一个DOM元素 选中一个元素,然后按h,这时候就会在选中的DOM元素上加上__web-inspector-hide-shortcut__类,这个类会让元素隐藏。谷歌和火狐上都可以,IE上没有试过行不行。

2018-02-08 09:10:59 · 1 min · Eddie Wang

直接在Chrome DevTools调试Node.js

英文好的,直接看原文 https://blog.hospodarets.com/nodejs-debugging-in-chrome-devtools 1. 要求 Node.js 6.3+ Chrome 55+ 2. 操作步骤 1 打开连接 chrome://flags/#enable-devtools-experiments 2 开启开发者工具实验性功能 3 重启浏览器 4 打开 DevTools Setting -> Experiments tab 5 按6次shift后,隐藏的功能会出现,勾选"Node debugging" 3. 运行程序 必须要有 --inspect > node --inspect www Debugger listening on port 9229. Warning: This is an experimental feature and could change at any time. To start debugging, open the following URL in Chrome: chrome-devtools://devtools/remote/serve_file/@60cd6e859b9f557d2312f5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=localhost:9229/78a884f4-8c2e-459e-93f7-e1cbe87cf5cf 将这个地址粘贴到谷歌浏览器:chrome-devtools://devtools/remote/serve_file/@60cd6e859b9f557d2312f5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=localhost:9229/78a884f4-8c2e-459e-93f7-e1cbe87cf5cf 程序后端输出的日志也回输出到谷歌浏览器的console里面,同时也可以在Sources里进行断点调试了。

2018-02-07 14:15:43 · 1 min · Eddie Wang