Ninja 之路:试炼!求生演习——异步 I/O、http
鸣人火影之路的第一步,就是跟着卡卡西学习基本的忍术,让自己先在忍者的世界里生存下来,so,想要在 node 的世界里游刃有余,必须要掌握异步 I/O、http等核心技能。
ok,第一步先学会读懂需求
// NO1:
// Create a program that prints a list of files in a given directory,filtered by the extension of the files. You will be provided a directory name as the first argument to your program (e.g. '/path/to/dir/') and a file extension to filter by as the second argument. For example, if you get 'txt' as the second argument then you will need to filter the list to only files that end with .txt. Note that the second argument will not come prefixed with a '.'. The list of files should be printed to the console, one file per line. You must use asynchronous I/O. // tips
// The fs.readdir() method takes a pathname as its first argument and a callback as its second. The callback signature is: function callback (err, list) { /* ... */ } // where list is an array of filename strings. //You may also find node's path module helpful, particularly the extname method.
// The answer at the bottom
// NO2:
// This problem is the same as the previous but introduces the concept of modules. You will need to create two files to solve this.
// Create a program that prints a list of files in a given directory, filtered by the extension of the files. The first argument is the directory name and the second argument is the extension filter. Print the list of files (one file per line) to the console. You must use asynchronous I/O.
// You must write a module file to do most of the work. The module must export a single function that takes three arguments: the directory name, the filename extension string and a callback function, in that order. The filename extension argument must be the same as what was passed to your program. Don't turn it into a RegExp or prefix with "." or do anything except pass it to your module where you can do what you need to make your filter work.
// The callback function must be called using the idiomatic node(err, data) convention. This convention stipulates that unless there's an error, the first argument passed to the callback will be null, and the second will be your data. In this exercise, the data will be your filtered list of files, as an Array. If you receive an error, e.g. from your call to fs.readdir(), the callback must be called with the error, and only the error, as the first argument.
// You must not print directly to the console from your module file, only from your original program. // These four things are the contract that your module must follow.
// 1. Export a single function that takes exactly the arguments described.
// 2. Call the callback exactly once with an error or some data as described.
// 3. Don't change anything else, like global variables or stdout.
// 4. Handle all the errors that may occur and pass them to the callback. // The benefit of having a contract is that your module can be used by anyone who expects this contract. So your module could be used by anyone else who does learnyounode, or the verifier, and just work. // tips
// The answer at the bottom
// Create a new module by creating a new file that just contains your directory reading and filtering function. To define a single function export, you assign your function to the module.exports object, overwriting what is already there: module.exports = function (args) { /* ... */ } // Or you can use a named function and assign the name. // To use your new module in your original program file, use the require() call in the same way that you require('fs') to load the fs module. The only difference is that for local modules must be prefixed with './'. So,
// if your file is named mymodule.js then: var mymodule = require('./mymodule.js')
怎么样?是不是发现自己有时连需求都看不懂!没关系,下面就是中文了,不过最新的、高质量的新技术都是通过英语来传播的,所以最好还是坚持学英语,读英语技术书籍、博客!
// NO3
// 这次的问题需要使用到 http.get() 方法。然而,这一次,将有三个 URL 作为前三个命令行参数提供给你。
// 你需要收集每一个 URL 所返回的完整内容,然后将它们在终端(标准输出stdout)打印出来。这次你不需要打印出这些内容的长度,仅仅是内容本身即可(字符串形式);每个 URL 对应的内容为一行。重点是你必须按照这些URL在参数列表中的顺序将相应的内容排列打印出来才算完成。 // 提示
// 不要期待这三台服务器能好好的一起玩耍!他们可能不会把完整的响应的结果按照你希望的顺序返回给你,所以你不能天真地只是在收到响应后直接打印出来,因为这样做的话,他们的顺序可能会乱掉。
// 你需要去跟踪到底有多少 URL 完整地返回了他们的内容,然后用一个队列存储起来。一旦你拥有了所有的结果,你才可以把它们打印到终端。
// NO4:编写一个 TCP 时间服务器 // 你的服务器应当监听一个端口,以获取一些 TCP 连接,这个端口会经由第一个命令行参数传递给你的程序。针对每一个 TCP 连接,你都必须写入当前的日期和24小时制的时间,如下格式: // "YYYY-MM-DD hh:mm" // 然后紧接着是一个换行符。 // 月份、日、小时和分钟必须用零填充成为固定的两位数: // "2013-07-06 17:42" // 提示
// 这次练习中,我们将会创建一个 TCP 服务器。这里将不会涉及到任何 HTTP 的事情,因此我们只需使用 net 这个 Node 核心模块就可以了。它包含了所有的基础网络功能。 // net 模块拥有一个名叫 net.createServer() 的方法,它会接收一个回调函数。和 Node 中其他的回调函数不同,createServer() 所用的回调函数将会被调用多次。你的服务器每收到一个 TCP 连接,都会调用一次这个回调函数。这个回调函数有如下特征: function callback (socket) { /* ... */ } // net.createServer() 也会返回一个 TCP 服务器的实例,你必须调用 server.listen(portNumber) 来让你的服务器开始监听一个特定的端口。 // 一个典型的 Node TCP 服务器将会如下所示: var net = require('net')
var server = net.createServer(function (socket) {
// socket 处理逻辑
})
server.listen(8000) //socket 对象包含了很多关于各个连接的信息(meta-data),但是它也同时是一个 Node 双工流(duplex Stream),所以,它即可以读,也可以写。对这个练习来说,我们只需要对 socket 写数据和关闭它就可以了。 // 使用 socket.write(data) 可以写数据到 socket 中,用 socket.end() 可以关闭一个 socket。另外, .end() 方法也可以接收一个数据对象作为参数,因此,你可简单地使用 socket.end(data) 来完成写数据和关闭两个操作。
// NO5
// 编写一个 HTTP 文件 服务器,它用于将每次所请求的文件返回给客户端。 你的服务器需要监听所提供给你的第一个命令行参数所制定的端口。 同时,第二个会提供给你的程序的参数则是所需要响应的文本文件的位置。在这一题中,你必须使用 fs.createReadStream() 方法以 stream 的形式作出请求相应。
// 提示
//一个典型的 Node HTTP 服务器将会是这个样子: var http = require('http')
var server = http.createServer(function (req, res) {
// 处理请求的逻辑...
})
server.listen(8000) // fs 这个核心模块也含有一些用来处理文件的流式(stream) API。你可以使用 fs.createReadStream() 方法来为命令行参数指定的文件创建一个 stream。这个方法会返回一个 stream 对象,该对象可以使用类似 src.pipe(dst) 的语法把数据从 src流传输(pipe) 到 dst流中。通过这种形式,你可以轻松地把一个文件系统的 stream 和一个 HTTP 响应的 stream 连接起来。
// NO6
// 编写一个 HTTP 服务器,它只接受 POST 形式的请求,并且将 POST 请求主体(body)所带的字符转换成大写形式,然后返回给客户端。 // 提示
// through2-map 允许你创建一个 transform stream,它仅需要一个函数就能完成「接收一个数据块,处理完后返回这个数据块」 的功能 ,它的工作模式类似于 Array#map(),但是是针对 stream 的: var map = require('through2-map')
inStream.pipe(map(function (chunk) {
return chunk.toString().split('').reverse().join('')
})).pipe(outStream)
// NO7 HTTP JSON API 服务器 // 编写一个 HTTP 服务器,每当接收到一个路径为 '/api/parsetime' 的 GET 请求的时候,响应一些 JSON 数据。我们期望请求会包含一个查询参数(query string),key 是 "iso",值是 ISO 格式的时间。 /api/parsetime?iso=2013-08-10T12:10:15.474Z // 所响应的 JSON 应该只包含三个属性:'hour','minute' 和 'second'。例如: {
"hour": 14,
"minute": 23,
"second": 15
} // 然后增再加一个接口,路径为 '/api/unixtime',它可以接收相同的查询参数(query string),但是它的返回会包含一个属性:'unixtime',相应值是一个 UNIX 时间戳。例如: { "unixtime": 1376136615474 } //提示
// 你可以使用 Node 的核心模块 'url' 来处理 URL 和 查询参数(query string)。 url.parse(request.url, true) 方法会处理 request.url,它返回的对象中包含了一些很有帮助的属性,方便方便你处理 querystring。
// 你也应当争做 Web 世界的好公民,正确地为响应设置 Content-Type 属性: res.writeHead(200, { 'Content-Type': 'application/json' })
Pseudo code
// NO1
var fs = require('fs')
var path = require('path') var folder = process.argv[2]
var ext = '.' + process.argv[3] fs.readdir(folder, function (err, files) {
if (err) return console.error(err)
files.forEach(function (file) {
if (path.extname(file) === ext) {
console.log(file)
}
})
})
// NO2
// ./solution/solution.js_ : var filterFn = require('./solution_filter.js')
var dir = process.argv[2]
var filterStr = process.argv[3] filterFn(dir, filterStr, function (err, list) {
if (err) {
return console.error('There was an error:', err)
} list.forEach(function (file) {
console.log(file)
})
}) // ./solution/solution_filter.js_ : var fs = require('fs')
var path = require('path') module.exports = function (dir, filterStr, callback) {
fs.readdir(dir, function (err, list) {
if (err) {
return callback(err)
} list = list.filter(function (file) {
return path.extname(file) === '.' + filterStr
}) callback(null, list)
})
}
// NO3
var http = require('http');
var i = 2,
aCon = []; function filterFn(aUrl) { if (i < 5) {
http.get(aUrl[i], function (res) {
res.setEncoding('utf8');
let rowData = ''; res.on('data', function (data) {
rowData += data;
}).on('end', ()=>{
i++;
aCon.push(rowData);
filterFn(aUrl);
}).on('error', (e) => {
console.log($(e.message));
});
});
} else {
aCon.forEach(function (val) {
console.log(val);
});
}
} filterFn(process.argv);
// NO4
var net = require('net') function zeroFill (i) {
return (i < 10 ? '0' : '') + i
} function now () {
var d = new Date()
return d.getFullYear() + '-' +
zeroFill(d.getMonth() + 1) + '-' +
zeroFill(d.getDate()) + ' ' +
zeroFill(d.getHours()) + ':' +
zeroFill(d.getMinutes())
} var server = net.createServer(function (socket) {
socket.end(now() + '\n')
}) server.listen(Number(process.argv[2]))
// NO5
var http = require('http')
var fs = require('fs') var server = http.createServer(function (req, res) {
res.writeHead(200, { 'content-type': 'text/plain' }) fs.createReadStream(process.argv[3]).pipe(res)
}) server.listen(Number(process.argv[2]))
// NO6
const server = http.createServer((req, res) => {
if (req.method != 'POST') {
return res.end('send a POST\n');
} req.pipe(map(function (chunk) {
return chunk.toString().toUpperCase();
})).pipe(res);
}); server.listen(Number(process.argv[2]));
// NO7
var http = require('http')
var url = require('url') function parsetime (time) {
return {
hour: time.getHours(),
minute: time.getMinutes(),
second: time.getSeconds()
}
} function unixtime (time) {
return { unixtime: time.getTime() }
} var server = http.createServer(function (req, res) {
var parsedUrl = url.parse(req.url, true)
var time = new Date(parsedUrl.query.iso)
var result if (/^\/api\/parsetime/.test(req.url)) {
result = parsetime(time)
} else if (/^\/api\/unixtime/.test(req.url)) {
result = unixtime(time)
} if (result) {
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify(result))
} else {
res.writeHead(404)
res.end()
}
})
server.listen(Number(process.argv[2]))
PS: nodeSchool
Ninja 之路:试炼!求生演习——异步 I/O、http的更多相关文章
- 嵌入式Linux驱动学习之路(十三)按键驱动-异步通知
之前的按键方式: 查询: 极度占用CPU资源 中断: 在读的时候产生休眠,在没有信号的时候永远不会返回. poll机制: 在中断的基础上加上超时时间. 异步通知就是通过信号来传送. 首先在应用程序中有 ...
- IOS学习之路七(使用 Operation 异步运行任务)
在 application delegate 头文件(.h)中声明一个 operation 队列和两个 invocation operations: #import <UIKit/UIKit.h ...
- 【CLR VIA C#】读书笔记
工作几年了才看,记录下笔记备忘. 章节 笔记 1.CLR的执行模型 公共语言运行时(Common Language Runtime,CLR) 源代码-->编译器检查语法和分析源代码-->托 ...
- vue ssr 项目改造经历
vue ssr 项目改造经历 由于工作项目需求,需要将原有的项目改造,vue ssr 没有用到nuxt,因为vue ssr更利于seo,没办法,一个小白的改造经历, 首先说明一下,小白可以借鉴,高手也 ...
- Linux日志管理系统rsyslog
一.日志的概念 什么是日志?日志就是历史事件.历史事件包括时间.地点.人物.时间.这个是生活中所说的日志很好理解.在Linux中也有类似的服务,它主要作用就是记录Linux系统的历史事件,包括什么时间 ...
- Python之路,Day10 - 异步IO\数据库\队列\缓存
Python之路,Day9 - 异步IO\数据库\队列\缓存 本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitM ...
- Node.js之路【第三篇】NodeJS异步实现
NodeJS异步实现 Node.js异步编程的直接体现就是回调,它依托于回调来实现,但不能说使用了回调他就是异步了 回调函数在完成任务后就会被调用,Node使用了大量的回调函数,Node所有的API都 ...
- Python之路第一课Day10--随堂笔记(异步IO\数据库\队列\缓存)
本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitMQ队列 Redis\Memcached缓存 Paramiko SS ...
- EF架构~EF异步改造之路~仓储接口的改造
回到目录 返回异步与并行目录 C#5.0带来了并行编程 {C#1.0托管代码→C#2.0泛型→C#3.0LINQ→C#4.0动态语言→C#5.0异步编程} 随着C#5.0在.net4.5出来之后,它们 ...
随机推荐
- db2 sequence 查询
1. 查询名字 select * from sysibm.sysequences where seqname='wx_Id' 2.nextVal select wx_seq_id.currval fr ...
- 浩哥解析MyBatis源码(二)——Environment环境
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6625612.html 本应该先开始说Configuration配置类的,但是这个类有点过于 ...
- [敏捷开发实践](2) 用于开发和维持复杂产品的敏捷开发框架Scrum
[敏捷开发实践](2) 用于开发和维持复杂产品的敏捷开发框架Scrum 1,Scrum概述 上篇中提到敏捷开发有两种主流的方法,一个是XP,另一个是Scrum,本篇简要介绍Scrum方法.Scrum是 ...
- php写留言板
简单的PHP留言板制作 做基础的留言板功能 需要三张表: 员工表,留言表,好友表 首先造一个登入页面: <form action="drcl.php" method=&qu ...
- Zkui安装
是一个允许在zookeeper上进行增删查改操作的图形管理工具,与zkdash类似. 1.拉取代码 #git clone https://github.com/DeemOpen/zkui.git 2. ...
- centos下编译phantomjs2.0
phantomjs是一个无头浏览器,可以用来做测试和爬虫,但是因为有一些问题没有解决,所以官网不提供2.0版本的binary包,所以要自己编译. 1.安装需要的依赖: sudo yum -y inst ...
- shiro使用教程
一.shiro是什么 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.不仅可以在Web项目中使用,在普通的项目中也是可以使用的 二.shiro可以做什 ...
- String 类的实现(1)浅拷贝存在的问题
浅拷贝 : 也称位拷贝 , 编译器只是直接将指针的值拷贝过来, 结果多个对象共用 同 一块内 存, 当一个对象将这块内 存释放掉之后, 另 一些对象不知道该块空间 已经还给了 系 统, 以 为还有效, ...
- 数位dp初步——数位dp的两种方式
数位dp:一类统计区间[L,R]内某种符合规定的数字个数的题目.特征是R的范围会很大,O(N)范围内无法完成. 一般而言,解决这类题目有两种方式,一种是递推,另一种是记忆化搜索. 递推: 1)利用dp ...
- ng自定义一个过滤器
ng允许我们自定义指令 下面来我们自己来定义一个过滤指令:filter,返回一个函数的形式 filter(name,callback(){//name:过滤器的名字,callback:匿名函数 ret ...