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出来之后,它们 ...
随机推荐
- 车大棒浅谈jQuery源码(一)
背景 因为最近辞职找工作,投了许多家公司.结果简历要么石沉大海,一点音讯都没有,要么就是邮件回复说不匹配.后面加了一些QQ群,才发现原来我工作经验年限太少了.现在深圳都是3经验起步,北京据说更加恐怖. ...
- 关于Android开发的几点建议
绝不要在UI线程中做数据处理的工作,这会让你的app变慢,带来极差的用户体验. 要按照google发布的Design指导意见来设计app,比如一个holo主题app会给用户带来更好的用户体验. 不要复 ...
- 常见排序算法-Python实现
常见排序算法-Python实现 python 排序 算法 1.二分法 python 32行 right = length- : ] ): test_list = [,,,,,, ...
- iOS 内存泄漏
我一直以为现在都是自动内存管理了,还哪有什么内存泄漏啊.一检测才知道,不是我太相信Xcode了,就是我太单纯了.iOS开发中遇到的内存泄漏主要有几下几种: (1)对象不能释放.使用Core Fou ...
- web与request
request --> 封装了客户端所有的请求数据! 请求行 请求头 空行 请求体(GET没体) 回忆一下http协议!请求协议中的数 ...
- Spark踩坑记——共享变量
[TOC] 前言 Spark踩坑记--初试 Spark踩坑记--数据库(Hbase+Mysql) Spark踩坑记--Spark Streaming+kafka应用及调优 在前面总结的几篇spark踩 ...
- javaScript对象学习笔记(一)
一.什么是对象 对象: JavaScript的一种基本数据类型 对象是属性的无序集合,每个属性都是一个名/值对 JavaScript中的事物都是对象:字符串.数值.数组.函数... JavaScrip ...
- socket bind详解
http://www.cnblogs.com/nightwatcher/archive/2011/07/03/2096717.html 在最开始接触bind的时候,只是在写基于tcp的server端的 ...
- shell脚本编写步骤及其常用命令和符号
1,什么是Shell Shell 是kernel的一个外壳,是一个命令解析器,负责用户与内核的交互.2,Shell脚本 Shell脚本类似于批处理,可以方便的执行大量命令.3,编写sh ...
- JavaScript基础学习(九)—DOM
一.DOM概述 DOM(Document Object Model)文本对象模型. D: 文档,HTML文档或XML文档. O: 对象,document对象的属性和方法. ...