今晚3.8日直播讲京东抢购的网络请求分析,有想看的小伙伴备注python数据加我微信lujqme我拉你入群。
或者对数据感兴趣的朋友们也欢迎呢~
另外北京 数据岗求职,谢谢大家
今晚3.8日直播讲京东抢购的网络请求分析,有想看的小伙伴备注python数据加我微信lujqme我拉你入群。
或者对数据感兴趣的朋友们也欢迎呢~
另外北京 数据岗求职,谢谢大家
nuxtjs+express+vue2.0+vuex搭建的服务端渲染个人网站项目.<br> github项目地址: https://github.com/se7en-1992/5se7en.com项目线上地址:https://5se7en.com/
这里先说两句题外话,谈一谈对前端开发产生了深远影响的两个时间点<br>
^8.9.4
^4.16.2
^1.0.0-rc11
^2.5.3
npm install
npm run dev
使用浏览器打开 http://localhost:5757
assets
components
layouts
middleware
pages
plugins
static
store
config
start.js
13/50*100的值没问题,是26
element的表格排序怎么做? :default-sort = "{prop: ‘date’, order: ‘descending’}"做到的只是把原来的顺序调个个儿,可是原数据就是乱的。。。不会,求大神告知,感激不尽
本文非原创,原文在这里有如下表数据
+----+------+
| id | type |
+----+------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
| 6 | 3 |
| 7 | 3 |
| 8 | 4 |
| 9 | 4 |
| 10 | 4 |
+----+------+
想要 type=3 的行排在前面,type为其他值的排在后面,可以这样写SQL:
SELECT * FROM test ORDER BY IF(type=3,0,1);
结果如下:
+----+------+
| id | type |
+----+------+
| 6 | 3 |
| 7 | 3 |
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
| 8 | 4 |
| 9 | 4 |
| 10 | 4 |
+----+------+
解释:
IF(type=3,0,1)
的意思是,对 type 附加一个一个隐藏属性,这个隐藏属性,可以是0或者1,也就是对 type进行排序的时候,优先判断type是不是等于3,如果是,返回0,不是,返回1。然后对type隐藏属性进行排序,也就是对0和1进行排序。
也就是说,可以IF语句,看成一个独立的column,然后进行排序,你可以在IF语句后添加排序条件ASC或者DESC,当然,默认的排序是ASC,可以不写,上面的例子,加入你想让type=3的数据排在后面,就可以IF语句后面添加DESC了,如下:
SELECT * FROM test IF(type=3,0,1) DESC;
结果如下:
+----+------+
| id | type |
+----+------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
| 8 | 4 |
| 9 | 4 |
| 10 | 4 |
| 6 | 3 |
| 7 | 3 |
+----+------+
另外,你在进行隐藏属性优先排序的同时,对于剩下的排序,你也可以另外进行ASC或者DESC的排序
上面的例子是满足单个条件,返回0 或者 1,如果需要用到一个范围呢?比如想让 type =2或者type=3的行排在前面呢?
可以使用 IN 语句
SELECT * FROM ORDER BY type IN(2,3) DESC
结果如下
+----+------+
| id | type |
+----+------+
| 4 | 2 |
| 5 | 2 |
| 6 | 3 |
| 7 | 3 |
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 8 | 4 |
| 9 | 4 |
| 10 | 4 |
+----+------+
上面 type IN(2,3) DESC
, type IN 语句进行判断,如果type的值在(2,3)里面,返回1,否则返回0,所以,满足条件的数据,因为返回值是1,进行DESC排序的时候,就被放在在最后。
其他情况类推
在以下几种种情况,nodejs需要新开子进程来进行相关操作
tar
、gcc
等nodejs中使用child_process
模块来对子进程进行生成、管理和通讯。网上关于这一块的介绍也不少,但是其中的细节感觉还是语焉不详,这里我们主要讨论3个问题(基于Linux平台):
spawn
、exec
、execFile
和fork
的区别spawn
、exec
、execFile
和fork
它们之间的调用关系如下
exec
│
execFile fork
│ │
└─────spawn─────┘ 用户层面
│
----------│------------------------
│
│ nodejs内部
│
spawn(位于lib/internal/child_process.js)
从上图可易知:
child_process.spawn
接下来我们依次讨论一下这几个函数。
spawn的用法文档上已经写得很清晰,我们这里讨论值得关注的地方
通过修改options.stdio
,可以将子进程的stdio可以绑定到不同的地方。options.stdio
可以接受两种类型的值:字符串或者数组
options.stdio
的值是字符串时,它有以下几种取值
pipe
: 相当于[“pipe”,“pipe”,“pipe”],子进程的stdio与父进程的stdio通过管道连接起来,ignore
: 相当于[“ignore”,“ignore”,“ignore”],子进程的stdio绑定到/dev/null
,丢弃数据的输入输出inherit
: 继承于父进程的相关stdio、即等同于[process.stdin, process.stdout, process.stderr]
或者[0,1,2]
,此时父子进程的stdio都是绑定到同一个地方。当options.stdio
的值是数组的时候,前三个元素分别代表stdin stdout stderr。如果数组的元素大于3,则会在父子进程之间建立 额外的通讯通道,它们的值可以是下面的其中之一
pipe
:额外的通讯通道通过管道通讯。管道的两端分别连接着父子进程,在父进程这边可以通过subprocess.stdio[n](n=0、1、2)
或者subprocess.stdin, subprocess.stdout, subprocess.stderr
来引用管道的一端,而子进程则可以通过process.stdin, process.stdout, process.stderr
来引用另外一端,详情可以见面的例子。ipc
:额外的通讯通道通过ipc channel通讯ignore
:绑定到/dev/null
,即丢弃数据的输入输出Stream
对象:额外的通讯通道通过nodejs中Stream
对象通讯,对象底层的文件描述符代表一个文件例如socket,tty、本地文件等。Stream
相似。null
和undefined
:对于前3个元素,它们会被设为pipe
,对于剩下的元素会被设置ignore
以下的例子,它将stdio绑定到不同的地方
"use strict";
const child_process = require("child_process");
const script = (function(data) {
console.log(data);
}).toString();
child_process.spawn("node", ["-e", `( ${script}("inherit,这一般个会写到控制台") )`], {
//子进程的stdio继承父进程的stdio,即控制台,因此会输出到控制台
stdio: [process.stdin, process.stdout, process.stderr]
});
const fd = require("fs").openSync("./node.log", "w+");
child_process.spawn("node", ["-e", `( ${script}("整数fd,这一般个会写到某个文件") )`], {
//stdio绑定到文件描述符fd,它代表文件node.log,因此会输出到该文件
stdio: [process.stdin, fd, fd]
});
const writableStream = require("fs").createWriteStream("./node.log", {
flags: "a",
fd: fd
});
child_process.spawn("node", ["-e", `( ${script}("stream,这一般个会写到某个文件") )`], {
//输出到流所代表的目的地,注意这个流必须要有文件描述符,否则会失败
//这个例子中它会输出到文件node.log
stdio: [process.stdin, writableStream, fd]
});
const script2 = (function(data) {
console.log(data);
process.stdout.end("hello");
}).toString();
const node = child_process.spawn("node", ["-e", `( ${script2}("pipe,只能通过父进程将它输出") )`], {
//子进程的stdio绑定到父进程的
stdio: ["pipe", "pipe", "pipe"]
});
node.stdout.on("data", function(data) {
//注意此时子进程的输出全都通过管道传递到父进程,注意这种方式和"inherit"的区别
console.log(String(data));
});
看文档时候我发现一个例子
// Open an extra fd=4, to interact with programs presenting a
// startd-style interface.
spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] });
从stdio
的值来看父子进程之间建立了额外的ipc通道,父进程可以很容易引用这些额外的ipc通道,但是我找了很久都没有发现子进程那边是如何使用这些额外的ipc通道,希望有大牛能告之。
生成子进程的时候如果传递了detached=true
,则效果是使得子进程成为新的session和group的leader,效果和SETSID(2)是类似的。但也是仅此而已了,它和守护进程并没有明显的关联,文档中特别指出
Note that child processes may continue running after the parent exits regardless of whether they are detached or not
说明子进程是可以继续运行下去的,无论detached=true
是否被设置,例如
"use strict";
const child_process = require("child_process");
child_process.spawn("ping", ["localhost"]);
setTimeout(function() {console.log("hello");}, 3000);
process.exit();
将上述代码保存到文件test.js
,然后从命令行运行node test.js
,则有以下输出
[chris@localhost node]$ node test.js
[chris@localhost node]$ ps -ef | grep -E 'ping|node'
root 621 1 0 Mar03 ? 00:00:00 /usr/sbin/mcelog --ignorenodev --daemon --foreground
chris 6364 1 0 04:01 pts/0 00:00:00 ping localhost
chris 6366 5514 0 04:01 pts/0 00:00:00 grep --color=auto -E ping|node
父进程启动ping
后就立即使用process.exit()
强行退出,这使得ping
成为孤儿进程并被init
进程(进程id为1)收养,从而使得ping
能够继续在后台运行,注意此时并没有设置detached=true
,此时即使你退出终端ping
命令依然在后台继续进程(有点像守护进程?)。
不过这种方法是有缺陷的,因为是强行退出的,父进程event loop中的内容尚未执行完退出了,我们需要一种优雅安全的退出方法。
首先删掉process.exit()
并设置detached=true
(如果不设置的话子进程在父进程结束后也会跟着结束)
"use strict";
const child_process = require("child_process");
child_process.spawn("ping", ["localhost"], {detached:true});
setTimeout(function() {console.log("hello");}, 3000);
此时setTimeout
的回调可以得到执行,但是父进程会等待子进程退出,用ctrl+c
结束父进程后子进程依然存活,并且被init
进程收养。因为文档中说明:
By default, the parent will wait for the detached child to exit. To prevent the parent from waiting for a given subprocess, use the subprocess.unref() method
默认情况下父进程会等待已经分离的子进程,可以调用subprocess.unref()
来取消等待。于是按照要求加上相关代码
"use strict";
const child_process = require("child_process");
const ping = child_process.spawn("ping", ["localhost"],{detached : true});
ping.unref();
setTimeout(function() {console.log("hello");}, 3000);
还是不行,父进程依然会等待子进程,再次查阅文档,原来还漏看了一句
unless there is an established IPC channel between the child and parent.
如果父子进程之间建立了的ipc,父进程还是会等待。根据我们上面的总结,推论将stdio
设置为ignore
、描述符、Stream
对象应该可以让父进程不再等待。
"use strict";
const fd = require("fs").openSync("./node.log", "w+");
const writableStream = require("fs").createWriteStream("./node.log", {
flags: "a",
fd: fd
});
const child_process = require("child_process");
const ping = child_process.spawn("ping", ["localhost"], {
detached: true,
stdio: ["ignore", fd, writableStream]
});
ping.unref();
setTimeout(function() {
console.log("hello");
}, 3000);
这次可以了,父进程在运行完自己的代码之后顺利退出,而子进程则继续在后台运行,同时被init
进程收养
总结:要想让程序成为守护进程,必须要做到
detached=true
unref()
exec
和execFile
先来看看exec
的源码
function normalizeExecArgs(command, options, callback) {
if (typeof options === 'function') {
callback = options;
options = undefined;
}
// Make a shallow copy so we don't clobber the user's options object.
options = Object.assign({}, options);
//如果指定了shell,则把它传递下去,否则将它设为true
options.shell = typeof options.shell === 'string' ? options.shell : true;
return {
file: command,
options: options,
callback: callback
};
}
exports.exec = function(command /*, options, callback*/) {
var opts = normalizeExecArgs.apply(null, arguments);
//其实就是简单调用execFIle
return exports.execFile(opts.file,
opts.options,
opts.callback);
};
原来就是调用execFile
,那么无需多言直接看execFile
就可以了,值得一提的是文档中说exec
会开启一个shell来执行命令,在代码中的体现是把options.shell
设置为true
,后续的函数根据这个来属性来决定是否开启一个shell执行命令。
再来看看exec
的源码的关键部分
exports.execFile = function(file /*, args, options, callback*/) {
//......
//直接调用spawn,但是传入了一些选项
var child = spawn(file, args, {
cwd: options.cwd,
env: options.env,
gid: options.gid,
uid: options.uid,
shell: options.shell,
windowsHide: !!options.windowsHide,
windowsVerbatimArguments: !!options.windowsVerbatimArguments
});
//......
//调用完spawn之后会缓存子进程的stdout和stderr
if (child.stdout) {
if (encoding)
child.stdout.setEncoding(encoding);//如果不是buffer类型,则是指编码
child.stdout.on('data', function onChildStdout(chunk) {
//如果是buffer类型,则加上收到的字节数,否则,加上收到的字符串
stdoutLen += encoding ? Buffer.byteLength(chunk, encoding) : chunk.length;
if (stdoutLen > options.maxBuffer) {//判断是否超出内部的buffer,如果你的子进程的输出很大,请注意调整这个参数
ex = new errors.RangeError('ERR_CHILD_PROCESS_STDIO_MAXBUFFER',
'stdout');
kill();
} else if (encoding) {
_stdout += chunk;//缓存字符串
} else {
_stdout.push(chunk);//缓存buffer
}
});
}
//......
//监听子进程io流的关闭和子进程的错误,用户提供的callback会在这里被调用
//上面被缓存的输出会当做参数传递过去
child.addListener('close', exithandler);
child.addListener('error', errorhandler);
return child;
};
从上述代码可以清晰看到execFile
就是调用了spawn
并且将子进程的输出缓存起来然后通过回调一次过返回给用户。spawn
中是通过监听stdio上面的事件来获取子进程的输出(并且输出还不是一次返回),这有些繁琐。execFile
对其适当地封装使之变成了我们熟悉的回调方式,这应该就是execFile
的优点。
值得注意的是里面作为缓存的buffer是有默认大小的(默认为200 x 1024个字节),在项目中曾经试过因为子进程的输出太大导致抛出异常,因此execFile
适合子进程的输出不是太大的情况,或者修改maxBuffer
提供更大的缓存空间。
fork
fork
的相关源码如下:
exports.fork = function(modulePath /*, args, options*/) {
//省略
var execArgv;
if (typeof options.stdio === 'string') {
options.stdio = stdioStringToArray(options.stdio);
} else if (!Array.isArray(options.stdio)) {
/*
这里的注释说明第4个元素的值是ipc,说明在父子进程之间除了stdio之外还有ipc通道可以进行通讯
详情可以见下面的stdioStringToArray函数
*/
// Use a separate fd=3 for the IPC channel. Inherit stdin, stdout,
// and stderr from the parent if silent isn't set.
options.stdio = options.silent ? stdioStringToArray('pipe') :
stdioStringToArray('inherit');
} else if (options.stdio.indexOf('ipc') === -1) {
throw new errors.Error('ERR_CHILD_PROCESS_IPC_REQUIRED','options.stdio');
}
//如果没有特地指定execPath则默认值为nodejs的启动路径的绝对值
options.execPath = options.execPath || process.execPath;
options.shell = false;
return spawn(options.execPath, args, options);
}
function stdioStringToArray(option) {
switch (option) {
case 'ignore':
case 'pipe':
case 'inherit':
return [option, option, option, 'ipc'];//第4个元素表示额外的ipc通道
default:
throw new errors.TypeError('ERR_INVALID_OPT_VALUE', 'stdio', option);
}
}
fork
也是相当简单,注意两个地方:
spawn
的时候传递的第一个参数默认是nodejs路径的绝对值这跟文档描述很契合,启动了一个独立nodejs子进程并且和它建立ipc通道
spawn
一开始我们就说明了,用户层面的spawn
调用了nodejs内部的spawn
来生成子进程,它们的源码如下:
var spawn = exports.spawn = function(/*file, args, options*/) {
var opts = normalizeSpawnArguments.apply(null, arguments);
var options = opts.options;
var child = new ChildProcess();//一个内部的child_process构造函数,位于lib/internal/child_process.js
debug('spawn', opts.args, options);
child.spawn({//调用js内部的spawn函数,位于lib/internal/child_process.js
//注意file和detached,待会看下c++是怎么使用它们
file: opts.file,
args: opts.args,
cwd: options.cwd,
windowsHide: !!options.windowsHide,
windowsVerbatimArguments: !!options.windowsVerbatimArguments,
detached: !!options.detached,
envPairs: opts.envPairs,
stdio: options.stdio,
uid: options.uid,
gid: options.gid
});
return child;
};
代码一目了然没什么好探讨的,可以说用户层面的child_process
其实是内部child_process
的一个封装,我们直接看内部的spawn
ChildProcess.prototype.spawn = function(options) {
//省略...
var err = this._handle.spawn(options);
//省略...
// Add .send() method and start listening for IPC data
if (ipc !== undefined) setupChannel(this, ipc);
return err;
};
内部的spawn
看似很长但是核心代码就两句,分别用于生成子进程和建立父子进程的通讯通道。其中this._handle.spawn
其实是调用了process_wrap.cc
的spawn
,这属于C++层面的东西,我们下个章节会对它进行简要的分析。
process_wrap.cc
的spawn
根据上面的分析,先来看process_wrap.cc
的spawn
关键代码
static void Spawn(const FunctionCallbackInfo<Value>& args) {
//获取js传过来的第一个option参数
Local<Object> js_options = args[0]->ToObject(env->context()).ToLocalChecked();
//提取option里面的参数,例如file和detached
// options.file
Local<Value> file_v = js_options->Get(context, env->file_string()).ToLocalChecked();
CHECK(file_v->IsString());
node::Utf8Value file(env->isolate(), file_v);
options.file = *file;
// options.detached
Local<Value> detached_v = js_options->Get(context, env->detached_string()).ToLocalChecked();
if (detached_v->IsTrue()) {
options.flags |= UV_PROCESS_DETACHED;
}
//调用uv_spawn生成子进程,并将父进程的event_loop传递过去
int err = uv_spawn(env->event_loop(), &wrap->process_, &options);
//省略
}
它的主逻辑也很简单,仅仅看注释就很清楚,先是提取js传递过来的参数,然后调用process.cc
中的 uv_spawn
。
process.cc
中的 uv_spawn
终于来到了真正做事的地方:uv_spawn
,它也是相当长,我们摘取核心部分来看看
int uv_spawn(uv_loop_t* loop,
uv_process_t* process,
const uv_process_options_t* options) {
//省略一堆设置stdio的初始化工作代码
err = uv__make_pipe(signal_pipe, 0);//建立父子进程之间的通讯通道,这个东西似乎是node内部使用的
pid = fork();//用fork生成一个子进程
if (pid == 0) {//如果是子进程,则执行uv__process_child_init然后退出
uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
abort();
}
//省略...
err = waitpid(pid, &status, 0);//等待子进程返回
//如果是父进程则继续往下执行,以下是一堆相关的收尾释放资源之类的操作
}
static void uv__process_child_init(const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
int error_fd) {
//哈哈,终于找到了设置detached=true的作用了
if (options->flags & UV_PROCESS_DETACHED)
setsid();
//省略一大堆代码
//最终是调用execvp来执行任务,注意最终运行的命令就是js中传递过来的file
execvp(options->file, options->args);
}
从上面代码可以看到主要做了两件事:
uv_spawn
调用了fork
来生成子进程execvp
来执行新任务(其实跟我们的预料是一样的,linux就提供了这两个函数,关于这个两个函数的具体用法大家请自行搜索,网上的介绍极其丰富,缺乏系统编程的知识真是不好读源码)
从注释可以看到js层面传递过去detached=true
和file
最终是如何被使用的。选取C++层面源码的时候我跳过了很多关于stdio的地方,这些细节我们都放在IPC再讨论(好吧,其实是好多没看明白,囧rz)
本来想讨论一下父子进程之间的IPC包括stdio细节的,但是发现IPC足够写n篇文章了,以后再独立开吧。
前段时间被人问到有没有文件分享的网站,给他推荐了 WeTransfer,但是试用下来不太理想比较慢。想了想这个应该比较简单,于是我们自己写了一个文件分享的网站 https://bugu.link。项目是开源的分为前后端两个部分:后端项目和 前端项目。后端采用:Node.js + Koa2 + MySQL + Redis;前端采用:React + Yax + ReactRouter。
附个图:
Github: http://github.com/midwayjs/pandora, 欢迎 PR、Issue 和 Star.
Pandora.js 阿里巴巴产出的一个Node.js 应用监控管理器,可以让您对自己的 Node.js 应用了若指掌,我们的目标就是让应用可管理、可度量、可追踪。
我们自 2014 年开始使用 Node.js 并参与运维工作,Pandora.js 是淘宝 Midway 团队这些年对企业环境 Node.js 运维监控的一个沉淀与总结。在发展的过程中,我们大量使用了社区的开源软件,这次 Pandora.js 的开源是对社区的回馈。希望 Pandora.js 能让 Node.js 更好的应用在专业的商业场景上,给予它更好的基础监控运维能力去服务大规模商业场景。
同时,这也是阿里巴巴开源的第一个使用了类型系统的 Node.js 软件。它使用的是 TypeScript,为 Pandora.js 带来了前所未有的逻辑健壮性。
欢迎您来体验,同时更欢迎您基于 Pandora.js 建构您的 Node.js 运维基础设施。
就像前面提到的一样,Pandora.js 是一个 Node.js 应用监控管理器。它集成了多种类型的能力诸如:监控、链路追踪、调试、进程管理等等。一个一个讲太过凌乱,这里分为几个大范畴:
上面提到的全部能力和数据,全部通过 RESTFul 接口或文本日志透出,您可以轻松的将其集成进您的监控管理系统(为了更好的配套,在不远的将来我们也会将我们的私有监控管理平台开源)。
这样的概括还是有些枯燥与难以理解,接下来会通过 Pandora.js dashboard的界面介绍几个主要特性,Pandora.js dashboard 是一个与 Pandora.js 相配套的单机可视化仪表。然后在文章的最后是一个可以跑起来的例子~
链路追踪是第一个要介绍的重量级特性,可以追踪每个业务请求的全过程,在运行时直观的看出接口或页面慢在哪里、错在哪里、超时在哪里。
听上去很厉害的样子,但实际使用起来很简单。您只需要简单的使用 Pandora.js 来启动您的应用,然后打开 Pandora.js dashboard 就可以看到您的业务链路的全部细节:
轻松识别慢链路和错误链路
调用了,哪里耗时多,一目了然
Pandora.js 为您默认提供了近百项开箱即用的默认监控指标,让您轻松的开始监控您的应用。
默认提供了,Node.js Runtime 指标,操作系统指标,HTTP Incoming 指标等等。
Node.js 指标,包含大量运行时指标
操作系统指标,包含 Load、CPU、内存、磁盘、网络、TCP 等各种指标
应用运行在生产环境,我们有太多想要知道和观察的数据了。以往我们都是写很多日志文件,查看分析十分麻烦。Pandora.js 的 Metrics 提供了 Gauge(瞬时)、Counter(计数)、Meter(流速)、Histogram(直方图) 等多种度量类型,您可以轻易地完成大部分的应用或业务指标。
下面是一个例子:
根据 Email 去 Gravatar 获取用户的 Profile。然后我想统计有多少次成功了,多少次失败了。(这个例子在文章后面有附上)
const {MetricsClientUtil} = require('dorapan'); // dorapan 是 pandora 的一个客户端 sdk
const client = MetricsClientUtil.getMetricsClient(); // 获得 Metrics 客户端
// 创建两个 Counter (计数)类型的指标
const successCounter = client.getCounter('custom', 'custom.gravatar.success');
const failCounter = client.getCounter('custom', 'custom.gravatar.fail');
// ...此处省略若干代码
const userAvatars = {};
const promises = [];
for(const user of rows) {
const profileUrl = gravatar.profile_url(user.email);
promises.push(urllib.request(profileUrl, {
followRedirect: true, dataType: 'json'
}).then((res) => {
if(typeof res.data === 'object') {
successCounter.inc(1);
userAvatars[user.email] = res.data;
} else {
failCounter.inc(1);
}
}));
}
await Promise.all(promises);
可以看到 Metrics 中已经出现了 Custom 分组:
当然还有更多的 Metrics 类型可以实践,请具体参见文档。
这个例子的演示依赖两个部件:
您最好在 Linux 系统安装,同时 Pandora.js 依赖 Node.js >= 8.0.0 (也就是当前的 LTS 版本。我们在 macOS 上指标有部分实现也可以。如果您是 Windows 用户的话,我只能说欢迎 PR)。
$ npm i pandora -g
安好后您会获得一个 pandora 命令。
$ npm i pandora-dashboard -g
然后您就可以启动 Pandora.js dashboard 了。
$ pandora start --name dashboard `pandora-dashboard-dir`
上面有个 command substitutionpandora-dashboard-dir
,它是 Pandora.js 注入的一个全局命令。用来输出 Pandora.js dashboard 的目录,然后 Pandora.js 会把它当成一个普通的项目来启动。
安装完 Dashboard 之后打开 http://127.0.0.1:9081
,您可以看到 Dashboard 这个应用,这就是 Pandora.js dashborad 自己。
我找到一个 Node.js 的 简单 MySQL CRUD 的例子来进行接下来的演示。当然我为了演示还做了一些修改。示例项目在 Github,Clone 它您也可以跑跑试试看。
在这个例子里主入口为 server.js
,在项目根目录运行下面的命令来初始化。
$ pandora init server.js
? Which type do you like to generate ? (Use arrow keys)
fork
❯ cluster
我选择了 Cluster,不过您可以选择任意一个,这两个选项的行为就像 PM2 一样。Fork 简单拉起 server.js ,而 Cluster 则用 Node.js 的 Cluster 模块启动 server.js (即 Master / Worker 模型)。
在初始化完后,将会生成一个 procfile.js
文件。这个文件用来定义项目结构,就像 PM2 的 Process file 一样。其实 procfile 就是 Process File 的简写。
然后我们运行 pandora start
来启动应用:
$ pandora start
Starting rest-crud at /xx/xxx/rest-crud
rest-crud started successfully! Run command [ pandora log rest-crud ] to get more information
先放问下 http://127.0.0.1:300/api/user
查看下简单的 CRUD 例子,稍微做点操作。
然后让我们无视 Run command [ pandora log rest-crud ]
这个提示,直接打开 http://127.0.0.1:9081/
,然后您将看到:
点击 Standard Output
按钮来查看控制台输出:
点击 Trace
查看所有的链路:
点击 Metrics
查看所有的 Metrics 指标:
Node.js 应用在运维方面依旧还是很薄弱,Pandora.js 所做的也只是一点点工作,帮忙开发者更加了解自己的应用,在问题来临时,不再迷惘,不再慌乱。
四年间,我们看到了 Node 的兴起,工具链的完善,也看到了应用场景的萎缩,产品的各种迭代和意外,唏嘘之余,依旧得做好分内之事,让 Node 在部门,在集团,乃至在业界都能有一些成长和突破,同时让自己看清和选择一条路,坚定的走下去。
最后,再一次欢迎您来体验,尝试基于 Pandora.js 来建构您的 Node.js 运维基础设施,让天下没有难管理的应用。
我们如何玩好互联网信息传播这个每天都重复的“囚徒游戏”呢?
由于互联网信息传播中信息提供者特征可识别性与其传播的信息历史可查询性,我们根据我们的经验为与我们打交道的信息提供者设置相应的权值,这里称为信誉权值。信誉权值越高说明信息提供者提供的信息就对于我们来说越有价值,我们就可以奖励回报为我们提供高价值信息的信息提供者与反馈提高其信誉权值。信誉权值越低说明信息提供者提供的信息就对于我们来说越没有价值,我们就可以惩罚隔离这些提供垃圾信息的信息提供者与反馈降低其信誉权值。
通过为信息提供者设置的个人可随时修改的信誉权值,我们可以非常有效率的与愿意提供高价值信息的高信誉权值的信息提供者达成信息传播的“合作”,拒绝并惩罚那些提供垃圾信息的低信誉权值的信息提供者的信息传播的“合作”。为了互联网信息传播这个天天重复的“囚徒游戏”能更好长久的玩下去,我们需要如《合作的进化》中的所有善良策略者一样,不能耍小聪明地对善良的高信誉权值的信息提供者的高价值信息传播的“合作”予以善良的回报。
详细地址: https://github.com/turenmianshi/turenmianshi/wiki/book3_chshttps://turenmianshi.github.io/turenmianshi/book3_chs.html
如果你也深受垃圾信息的荼毒,想让更多的相关的人看到,请转发
https://www.cockos.com/licecap/开始录屏 看官网 非常好用!!!
职位要求:
前端、算法、研发 Java、研发 C/C++ 岗位不限。
其他岗位公司也有招聘,具体职位详情请戳: https://campus.alibaba.com/positionList.htm感兴趣的邮件 bluetomlee@gmail.com
var engCompileData= .... ;
var data={
.......
};
var html= Eng_Nos( data , engCompileData );
document.body.innerHTML=html;
// 没了就这样 ( 仓库里 有个 demo 源码在页面内)
PingPong 金融是家极其低调又极具实力的独角兽公司,作为中国第一家获得欧洲支付牌照的民营公司,目前在跨境收款这个风口处于领先地位,B 轮融资 4 个亿,表示不差钱。先晒JD:
前端工程师职位描述(薪资 15-30K):
岗位职责 1.与设计师、产品经理、后端工程师紧密工作,实现产品 UI 和交互方面的开发需求,理解产品经理和设计师; 2.能高效完成产品的迭代和新需求的开发; 3.根据业务抽离出组件,进行组件化开发; 4.优化团队开发方式及流程、提升团队开发效率、推动团队技术发展;
岗位要求
1.3 年以上前端开发经验(工作优秀者至少 2 年以上) 2.精通主要的前端语言,熟悉页面架构和布局,能够准确细致规划 CSS 结构,熟悉网站 Div+CSS 标准化布局,制作符合 w3c 规范的页面,能够解决各种浏览器兼容性问题; 3.熟练使用HTML5/CSS3/nodejs; 4.熟练使用 Vue 以及其工作原理,熟悉 Vue 组件化; 5.熟悉 Webpack 等工具; 6.具备良好的表达能力,善于团队合作、具备非常良好的责任心以及 Owner 意识,具备独立解决问题能力;
有意向的请发简历到邮箱: jiwg#pingpongx.com,
其他岗位也招,请参考帖子: V2EX招聘
最后感谢各位的阅读.
学习到中间件connect时,提到他自带了两个模块 一个是logger 这个我上网搜索到已经分出改成morgan模块 那么另外一个是favicon,现在报错如下 TypeError: connect.favicon is not a function at Object.<anonymous> (/Users/johnny/Downloads/code/6/http.js:5:26) at Module._compile (module.js:660:30) at Object.Module._extensions…js (module.js:671:10) at Module.load (module.js:573:32) at tryModuleLoad (module.js:513:12) at Function.Module._load (module.js:505:3) at Function.Module.runMain (module.js:701:10) at startup (bootstrap_node.js:193:16) at bootstrap_node.js:617:3 johnnydeMacBook-Air:6 johnny$ 有木有大神告诉我 是什么原因…懵逼中额么么么
index.js已经更改了
res.render(‘main/index’, { title: ‘Express’ });
继承语法没有问题
将html文件从main文件夹拿出来后就可以继承了~
这继承出现问题是什么情况呢
error报错:
用koa2写接口,我在登陆成功的接口里写了类似如下代码
exports.signIn = async (ctx, next) => { //如果登陆成功 ctx.session.user=’…’ }
但是接下来我在另一个接口中却获取不到ctx.session这个值,中间件的使用方式以及options都与官网一致,看样子也是支持koa2的
const session = require(‘koa-session’); const Koa = require(‘koa’); const app = new Koa();
app.keys = [‘some secret hurr’];
const CONFIG = { key: ‘koa:sess’, /** (string) cookie key (default is koa:sess) / /* (number || ‘session’) maxAge in ms (default is 1 days) / /* ‘session’ will result in a cookie that expires when session/browser is closed / /* Warning: If a session cookie is stolen, this cookie will never expire / maxAge: 86400000, overwrite: true, /* (boolean) can overwrite or not (default true) / httpOnly: true, /* (boolean) httpOnly or not (default true) / signed: true, /* (boolean) signed or not (default true) / rolling: false, /* (boolean) Force a session identifier cookie to be set on every response. The expiration is reset to the original maxAge, resetting the expiration countdown. (default is false) / renew: false, /* (boolean) renew session when session is nearly expired, so we can always keep user logged in. (default is false)*/ };
app.use(session(CONFIG, app)); // or if you prefer all default config, just use => app.use(session(app));
环境如下:
“node”: "8.9.3" “koa”: “^2.2.0”, “koa-session”: “^5.0.0”
请问是哪里出了问题么
为什么cmd下执行NetStat -ano |findstr xxxx 查看xxxx端口的时候会出现一堆进程 正常貌似只有一俩个 但是 去服务器上查看了下服务器的端口的时候却出来一堆 (网上找的图) 类似这样的 是因为这样的,一直使用pm2 管理node进程,但是经常restart的是报错出来 重复监听端口, 有一次程序运行很卡很慢,有个方法是加了redis分布式锁的,正常情况下这个锁是毫秒级别消失的,但是那天却一直是自己锁过期时间才释放,感觉node运行不正常,然后就重启app 用pm2 restart一下,然后就报重复监听了,然后就用命令行强制杀死这个端口的进程。之后这个redis分布式锁就恢复正常了,说明程序也正常了? ps:初步估计是可能有流程没有callback…不知道是不是这个原因? 各位大佬有什么看法?
之前用过heap-dump 查找过内存泄漏,想问一下对于node应用来说像heap-dump,memcache 等npm包 是如何获取到V8 内存信息的呢? 还有如果想监控性能比如进程层面的堆内存情况,GC 时间,cpu使用等信息那要怎么获取呢? 是底层V8 暴露一些接口了么?
美资外企,不加班,员工友好,上下级和睦,薪资15k-30k,福利多多
工作地点 上海市浦东新区张江高科
招聘要求 本身就是nodejs开发,要求有2年以上相关经验;如果是转的,要求熟悉nodejs开发,并对nodejs很有兴趣 英语可以简单沟通,或nodejs基础扎实,可以不要求英语 快速学习能力
薪水待遇 看个人水平,如果你经验丰富,欢迎挑战高薪 如果你只有1,2年经验也没关系,这里有经验丰富的人带你,只要你可以快速学习 待遇范围(15k-30k) * 13薪 + 年终奖(1-2个月)+补助,上班不打卡,美资企业福利不用担心
职业发展 如果你是希望在金融领域发展的话,这里很适合,也会有区块链的项目 客户方都很友好,不存在加班压力 如果你将来走职业经理人路线,这里也很适合你
联系方式 Email: yolandali@zwhrconsulting.com(邮箱简历给我) Wechat: 570962030