一个星期没更新了 = =
一直在忙着重构代码,以及解决重构后出现的各种 bug
现在 CSS 也有一点了,是时候把遇到的各种坑盘点一下了
在加载云音乐听歌排行的时候,有时会出现一个奇怪的 bug:json 数据无法被解析。如下图:
在刷新页面后,问题就会得到解决。此后无论怎么刷新,问题也不会出现。
过一段时间再次打开页面,会出现相同的问题,刷新之后也可以解决。此时换用其他各种浏览器,都不会出现问题;但一段时间之后仍会重现一次。。。
那肯定不是浏览器的锅了。把 Response 的内容复制出来看看。
粘贴,格式化。VSCode 报出了 4 个警告和一个错误;再仔细看一眼,哎,怎么中途截断了?难道是收到的请求不全?
返回去看看接收请求收到的 JSON 文件:没错啊,是全的。当然了,因为接下来刷新几次之后就不会在遇到此问题了。在本地测试中也发现,只有服务器启动之后的第一次访问,才会出现这个问题。
找到输出的位置,在这里下断点,开始调试。
从 server.js 进来的时候,文件还没有被创建;到 36 行,建立请求;38 行,绑定事件回调;49 行,发送。
接收到数据,触发
事件,命中断点。
- response
解压缩,输出,这时候检查一下输出的文件,
。跑到下一步
- 0 KB
,传出文件名,这时候检查输出文件,
- callback
。
- 0 KB
等下!怎么会是
!这时文件还没有写入完成,就已经把文件名传给回调函数,然后开始读取了?!
- 0 KB
然后就进入了各种不明所以的内部库调用,跳出之后,检查输出文件,
。这里才刚刚写入完成!自然,浏览器那边还是没法解析,传出来的数据还是不完整,即使输出文件已经是完整的了。
- 37KB
有没有联想到一些东西?是 IO 效率的问题,或者说,文件操作也是异步的,需要等待一个事件?
好,马上去查一下,找到了
的
- Stream.Writable
事件。这个事件在所有数据写入完成之后被触发。好,要的就是你。
- finish
将代码修改如下:
- response.pipe(zlib.createGunzip()).pipe(output);
- // wait for file operation
- output.on('finish', () = >{
- fs.readFile(outputFileName, (err, data) = >{
- var buf = JSON.parse(data.toString())['/api/user/detail/76980626'].listenedSongs;
- bufJSON = new Array();
- buf.forEach((value, index) = >{
- if (index > 9) return;
- bufJSON.push({
- id: value.id,
- name: value.name,
- artistName: value.artists[0].name
- });
- });
- });
- });
在等待文件操作完成之后才读取数据,而且读到数据后,只取出自己需要用到的部分,存在全局数组
中当作缓存,顺便提高一下 API 响应速度。
- bufJSON
之前,API 获取的听歌排行目标用户是写死在代码里的。可以写一个
函数,初始化它的获取目标用户。
- init()
- function init(id) {
- userId = id;
- outputFileName = `netease_music_record_$ {
- id
- }.json`;
- }
在写入请求 body 的时候,要把请求数据转化成 QueryString 的格式。Node.js 提供的 QueryString 模块可以接受一个 Obejct 作为参数,输出字符串;不过可变值的多行字符串并不能作为对象的属性名。也就是说:
- var postData = {` / api / user / detail / $ {
- id
- }`: '{\'all\':true}'
- }
是会报错的,对象属性名非法。这下我们就需要引入
这个数据类型了,只要是合法的字符串,就可以当作数据的键和值。像这样:
- Map
- var req = http.request(options);
- var qString = new Map();
- qString[` / api / user / detail / $ {
- userId
- }`] = '{\'all\':true}';
- req.write(qs.stringify(qString));
嗯,API 的优化就说到这里了,代码都在文章最下方的 Git 仓库里,我也会时不时进行一些抽风似的重构,不可能一一讲述了。
说到动态页面,直接用 JS 在浏览器里操作不就行了,还关服务器什么事?这样虽然很方便,不过有一个弊端:不利于搜索引擎爬虫的索引。自己博客里写了这么多文章,当然希望更多的人可以通过搜索引擎找到,而不是整天放在那里无人问津吧。
好,那就来动态的构建一个 404 页面,可以显示当然服务器正在运行的 Node 版本。
之前我们的 404 页面是这样的。可现在 Node.js 的 current 版本已经到 6.4.0 了,就先从这里下手吧。
通过,了解到,要获取当前 node 版本号,只需要使用
。如何吧这个版本号替换进 404 页面的 html 文件中去呢?我想到的方法是,把 html 中的版本号改成一段特殊的字符串,然后用正则表达式去唯一的匹配他。比如这样:
- porcess.version
- <p>
- Node.js - ${process.version}
- </p>
然后我们建立正则表达式,去匹配那个字符串。但千万不要在 html 文档的其他地方使用这个 "占位符",它会被全部替换成版本号。也可以再在后面加一些其他无意义内容,反正要避免正常的代码或文字与它重复。
- fs.readFile(path.join(root, '/page/404.html'), (err, data) = >{
- var versionRegex = /\$\{process\.version\}/;
- var nodeVersion = process.version;
- var current404 = data.toString().replace(versionRegex, nodeVersion);
- var page404 = fs.createWriteStream(path.join(root, '/page/current404.html'));
- page404.end(current404, 'utf8');
- });
读取文件,转换字符串,然后生成了新的
文件。之后发送 404 页面的响应也要改成发送刚刚生成的
- current404.html
。
- current404.html
把这段代码放在
靠前的部分,相当于变量初始化的位置,然后运行测试吧:
- server.js
好的,效果达到了。
Ajax 都很熟悉吧,
,再加上
- Asynchronous Javascript And XML
,就变成了
- pushState
。
- Pjax
没什么神秘的,
的作用就是,改变页面的 URL,并将一个
- history.pushState()
对象储存起来。这个
- state
对象是自己定义的。在事件
- state
的回调函数中,传入的参数的
- window.onpopstate
属性,是之前储存起来的
- state
对象。
- state
简单来说,使用
,会改变当前页面的 URL,但仅仅是改变,浏览器并不尝试去加载他,只是摆在那里;同时会将 URL 与传入的
- history.pushState()
对象一起压入历史纪录栈中。当用户操作浏览器前进或后退时,如果操作后当前页面的 URL 是由
- state
方法压入栈中的,那么页面将不会被重新加载,
- history.pushState()
的回调函数会被执行。
- window.onpopstate
有关更详细的介绍,请看。
我的目的是,在用户单击了首页的标题文章标题时,URL 改变,但以 Ajax 的方法从服务器加载文章内容,显示在页面上。而当用户直接访问这个 URL 时,又能提供完整文章浏览的页面。
为此,先要在主页上动动手脚,使得点击文章之后让他看起来像一个浏览页面:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>
- Rocka's Node Blog
- </title>
- </head>
- <body>
- <h1>
- Rocka's Node Blog
- </h1>
- <hr>
- <h3 id="index-article-title" style="display:none;">
- Title should be shown here.
- </h3>
- <blockquote id="index-article-content" style="display:none;">
- Article should be shown here.
- </blockquote>
- <h3 id="index-article-header">
- Blog Archive
- </h3>
- <ul id="index-article-list">
- </ul>
- <h3>
- Rcecntly Listened
- </h3>
- <ul id="index-music-record">
- </ul>
- </body>
来源: http://www.cnblogs.com/rocket1184/p/nodejs-heroku-blog-4.html