这个错误可能是由两个原因引起的。
xcode
重装 xcode
$ sudo rm -rf /Library/Developer/CommandLineTools $ xcode-select --install
node-gyp
重装 node-gyp。例如直接用 nvm 装一个新版的 node 即可。
这个错误可能是由两个原因引起的。
重装 xcode
$ sudo rm -rf /Library/Developer/CommandLineTools $ xcode-select --install
重装 node-gyp。例如直接用 nvm 装一个新版的 node 即可。
最近手痒造的轮子。。一个可以用纯 JavaScript 撸 png 的库,在路由器、树莓派之类的平台上有画图需求的同学可以看看。 Github 地址:https://github.com/Lellansin/node-pnglib
npm install node-pnglib
使用 http server
const http = require('http');
const PNGlib = require('node-pnglib');
http.createServer(function (req, res) {
if(req.url == '/favicon.ico') return res.end('');
// width 100, height 40
let png = new PNGlib(100, 40);
// from (0, 20)
let lineIndex = png.index(0, 20);
for (let i = 0; i < 100; i++) {
// draw a line to (0, 75)
png.buffer[lineIndex + i] = png.color('blue');
}
res.setHeader('Content-Type', 'image/png');
res.end(png.getBuffer());
}).listen(3001);
Output:
保存文件
const fs = require('fs');
const PNGlib = require('node-pnglib');
let png = new PNGlib(150, 150);
for (let i = 20; i < 100; i++) {
for (let j = 20; j < 100; j++) {
png.setPixel(i + 10, j + 25, '#cc0044');
png.setPixel(i + 20, j + 10, '#0044cc');
png.setPixel(i + 30, j, '#00cc44');
}
}
fs.writeFileSync('./block.png', png.getBuffer());
Output:
来画几个波浪线
const http = require('http');
const PNGlib = require('node-pnglib');
http.createServer(function (req, res) {
if(req.url == '/favicon.ico') return res.end('');
let png = new PNGlib(100, 100);
for (let i = 0; i < 65; i++) {
for (let j = 10; j < 65; j++) {
png.setPixel(i + 10, j + 20, '#cc0044');
png.setPixel(i + 20, j + 10, '#0044cc');
png.setPixel(i + 30, j, '#00cc44');
}
}
res.setHeader('Content-Type', 'image/png');
res.end(png.getBuffer());
}).listen(3001);
Output:
# 简单的划线
pnglib x 1,021 ops/sec ±3.37% (76 runs sampled)
pnglib-es6 x 3,293 ops/sec ±4.79% (79 runs sampled)
node-pnglib x 17,027 ops/sec ±0.93% (87 runs sampled)
Fastest is node-pnglib
node v8.1.1
MacBook Pro (Retina, 13-inch, Early 2015)
2.7 GHz Intel Core i5
比同类型库要快(单纯划线比原版要快 10+ 倍)。 你可以在这里 查看详细的基准测试内容。
应用上使用这个替换了 captchapng (因为这个库有没维护了所以撸了这些基础库) 发了个平滑迁移的 captchapng2。
之前用 captchapng 的同学欢迎转过来,有需求可以在 github 提,最近半年应该都会维护。
Node.js 的 8.0 版本终于发布了,等了两天没人测评,于是决定抛砖引玉。
首先需要说明的是,由于不方便拿业务代码测试来评测,所以本次基准测试(benchmark)毫无新意的沿用了 bluebird 的基准测试。测试比较的的内容是多个异步模式(async pattern)之间的性能对比。
目前 Node.js 业内比较异步模式性能比较靠谱的方式是基于 Gorki Kosev’s 的 《Analysis of generators and other async patterns in node》 的 benchmark。该 benchmark 模拟会模拟同时混合大量同步与异步操作的处理场景。具体指标是处理这些操作消耗的时间(ms)以及内存(MB)。
直接上一个 Node.js v8.0.0 的测试报告:
results for 10000 parallel executions, 1 ms per I/O op file time(ms) memory(MB) callbacks-baseline.js 328 24.11 callbacks-suguru03-neo-async-waterfall.js 409 35.66 promises-bluebird-generator.js 703 40.76 promises-bluebird.js 781 51.74 promises-then-promise.js 922 67.02 promises-cujojs-when.js 963 65.11 promises-lvivski-davy.js 1071 96.27 promises-tildeio-rsvp.js 1159 87.05 callbacks-caolan-async-waterfall.js 1345 102.79 promises-dfilatov-vow.js 1504 131.96 promises-calvinmetcalf-lie.js 1870 164.99 promises-ecmascript6-native.js 2167 167.91 promises-obvious-kew.js 2269 225.37 generators-tj-co.js 2273 119.98 observables-pozadi-kefir.js 3170 188.55 promises-medikoo-deferred.js 3202 114.25 observables-Reactive-Extensions-RxJS.js 4622 238.07 streamline-generators.js 6096 128.54 promises-kriskowal-q.js 12051 391.93 observables-caolan-highland.js 12269 534.94 streamline-callbacks.js 62359 198.94 observables-baconjs-bacon.js.js OOM OOM Platform info: Linux 2.6.32-042stab117.14 x64 Node.JS 7.7.4 V8 5.5.372.42 Intel(R) Xeon(R) CPU L5640 @ 2.27GHz × 2
其中的测试项中, 比较常见的详情分别是:
执行速度最快的还是原生的 callback

在内存占用方面可以看到 native 的 promise 较之前的版本有明显的下降,已经达到 async 模块的水平了。

完整执行数据 (ms)
| pattern | 6-1 | 6-2 | 7-1 | 7-2 | 8-1 | 8-2 |
|---|---|---|---|---|---|---|
| callbacks-baseline.js | 335 | 348 | 345 | 328 | 357 | 370 |
| callbacks-suguru03-neo-async-waterfall.js | 426 | 433 | 428 | 409 | 462 | 428 |
| promises-bluebird.js | 829 | 892 | 750 | 781 | 779 | 770 |
| promises-bluebird-generator.js | 838 | 973 | 707 | 703 | 782 | 789 |
| promises-cujojs-when.js | 916 | 961 | 978 | 963 | 977 | 965 |
| promises-then-promise.js | 827 | 913 | 940 | 922 | 987 | 1102 |
| promises-lvivski-davy.js | 1014 | 1149 | 1035 | 1071 | 1131 | 1142 |
| promises-tildeio-rsvp.js | 1085 | 1124 | 1189 | 1159 | 1186 | 1142 |
| promises-ecmascript6-native.js | 2530 | 2540 | 2286 | 2167 | 1216 | 1350 |
| callbacks-caolan-async-waterfall.js | 1317 | 1312 | 1427 | 1345 | 1433 | 1430 |
| generators-tj-co.js | 2753 | 2642 | 2267 | 2273 | 1616 | 1671 |
| promises-dfilatov-vow.js | 1382 | 1496 | 1665 | 1504 | 1688 | 1770 |
| promises-calvinmetcalf-lie.js | 1650 | 1795 | 1784 | 1870 | 2031 | 2177 |
| promises-obvious-kew.js | 2326 | 2421 | 2173 | 2269 | 2610 | 2667 |
| promises-medikoo-deferred.js | 4231 | 4416 | 3477 | 3202 | 3227 | 3048 |
| observables-pozadi-kefir.js | 60466 | 64587 | 3177 | 3170 | 3442 | 3161 |
| streamline-generators.js | 5533 | 6048 | 6682 | 6096 | 3013 | 3228 |
| streamline-callbacks.js | 8340 | 8784 | 79046 | 62359 | 4360 | 4339 |
| observables-Reactive-Extensions-RxJS.js | 4488 | 4947 | 4514 | 4622 | 5614 | 5578 |
| observables-caolan-highland.js | 152903 | 164368 | 12903 | 12269 | 17796 | 17243 |
| promises-kriskowal-q.js | 14618 | 15963 | 13198 | 12051 | 21159 | 19219 |
| observables-baconjs-bacon.js.js | 37014 | 33282 | – | – | 45257 | – |
完整内存数据 (MB)
PS:目前该 benchmark 尚未加入 async/await (笔者已经提了 issue,在考虑要不要自己撸),加入之后会更新本文。
简单的说, 在 Node.js 中使用 fs 读取文件的时候, 经常碰到要拼一个文件的绝对路径的问题 (fs 处理相对路径均以进程执行目录为准). 之前一直的方法都是, 使用 path 模块以及 __dirname 变量 :
fs.readFileSync(path.join(__dirname, './assets/some-file.txt'));
使用 require.resolve 可以简化这一过程:
fs.readFileSync(require.resolve('./assets/some-file.txt'));
此外, require.resolve 还会在拼接好路径之后检查该路径是否存在, 如果 resolve 的目标路径不存在, 就会抛出 Cannot find module './some-file.txt' 的异常. 省略了一道检查文件是否存在的工序 (fs.exists).
这个报错并不会加重你的检查负担, 毕竟使用 fs 去操作文件时, 如果发现文件不存在也会抛出异常. 反之, 通过 require.resovle 可以在提前在文件中作为常量定义, 那么在应用启动时就可以抛异常, 而不是等到具体操作文件的时候才抛异常.