20.Nodejsの基礎(中) - 2019年12月16日

2019年12月16日18時五十八分55秒

2019年10月4日12時20分59秒

はじめに1. nodejs

Node.jsのJavaScriptが開発サーバーで実行されているようにするプラットフォームであり、それは、JavaScriptの触手サーバは、PHP、JSP、PythonやRubyので後書き等しくすることができることができます。

しかし、ノードは少し違うようです。

Node.jsのは、別の言語ではない PHP、JSP、パイソン、Perlの、と、 Rubyはある「言語、ほかのプラットフォームだけではなく、」異なる、のNode.jsのJavaScriptプログラミング使用(V8)に、JavaScriptエンジンの実行を。

●などPHP、JSP、(PHP、JSP、サーバー上のプログラムを実行するには、.NETの必要性は、Apache、Naginx、Tomcatの、IIS。)と比較すると、Node.jsのは、Apacheのは、Naginx、IISや他のHTTPサーバをスキップし、独自の任意のサーバーソフトウェア上に構築しません多くのデザインと古典的なアーキテクチャ(LAMP =のLinux + Apacheの+のMySQLのNode.js + PHP)は、非常に異なっている強力なスケーラビリティを提供することができます。我々が表示されますが、何のWebコンテナは、Node.jsのありません。

自身の哲学のNode.js、それは、最小限のハードウェアコスト、高い同時実行性の追求、高い処理性能を過ごすことです。

特長:

いわゆる特性は、Node.jsのがボトルネックの問題を解決する方法である高性能サーバです。

1.1シングルスレッド

サーバー側の言語のJava、PHPや.NETなどでは、各クライアント接続のための新しいスレッドを作成します。そして、各スレッドは、メモリの2メガバイトほどかかります。つまり、理論的には、8GBのサーバができるユーザーの同時接続の最大数は4000程度です。より多くのユーザーをサポートするために、Webアプリケーションをしてみましょう、我々が増加して、当然のことながら、Webアプリケーションをサーバーの数、およびハードウェアのコストを増加させる必要があります。

Node.jsのは、新しいスレッドが、唯一つのスレッドを作成するために、各クライアントに接続されていません。ユーザが接続されている場合、それはマクロプログラムは、並列のNode.jsように、非ブロッキングI / O、イベント駆動型機構を介して、内部イベントをトリガします。使用のNode.js、40,000人以上の同時ユーザー接続を処理できる8GBのメモリサーバ。

また、シングルスレッドのメリットだけでなく、オペレーティングシステムは、完全に作成スレッドもはや破壊時のオーバーヘッドはありません。

害がユーザスレッドの崩壊によって引き起こされ、全体のサービスは、他の人が崩壊した、崩壊しました。

画像-20191004123038963

マルチスレッド、シングルスレッドの比較。

つまり、単一のスレッドも、マクロの「同時性」を引き起こす可能性があります。

1.2 I / OのI / O非ブロック非ブロック

例えば、取得したデータがデータベースにアクセスする際に、ある程度の時間がかかります。伝統的なシングルスレッド処理機構では、アクセスするためのコードの実装データベースの後、全体のスレッドが一時停止し、データベースの待機は、コードの背後を実行するために結果を返すこと。換言すれば、I / O大幅プログラムの実装の効率を低下させるコードの実行を阻止します。

Node.jsの非ブロッキングI / O機構の後に採用されているので、データベースへのコードのアクセスが実行されるように、直ちにコードの後ろに、代わりに実行されるデータベースに戻り、コールバック関数に処理コードの結果が、それによって改善プログラムの効率。

I / Oが終了すると、フォームは、このイベントのために実行I / O操作のイベント通知スレッドとスレッドのコールバック関数になります非同期I / Oを処理するために、スレッドはイベントループを持っている必要があり、常にチェック順番に対処すべき保留中のイベントは、存在しません。

ブロッキングモード、スレッドのみである必要があり、スループットを向上させるために、一つのタスクを扱うことができるマルチスレッド。非ブロッキングモードでは、スレッドは常に計算操作を実行する、スレッドCPUコア使用率は常に100%です。だから、これは特に哲学的なソリューションです。その人たちが、人々のアイドルの多く;あなたの人生は人、キル働いて子供のようではありません。

1.3イベントドリブンイベントドリブン

ノードでは、クライアントは、データや他の行為を提出し、接続を確立するために要求し、対応するイベントがトリガされます。ノードでは、一瞬で、あなただけのコールバック・イベントが、途中で実行するためのイベントのコールバック関数を実行することができます、あなたは(たとえば、別の新しいユーザーが接続されている)他のイベントに回し、その後、元のイベントを継続して戻ることができますコールバック関数、「イベントループ」機構として知られているこの処理機構。

Node.jsのは(V8はC ++で書かれている)基本的なC ++です。ほぼ半数のための基礎となるコード、イベントキューは、コールバックキューを構築しています。悪魔を考えているタスクを完了するためにイベントドリブンスケジューリングサーバ。スレッドに、先端の上で踊って、タスクの多くに対処するためのミッションを取ります。

画像-20191004124914552

シングルスレッドのメリット、シングルスレッド、縮小メモリのオーバーヘッド、オペレーティングシステム、メモリのページング。

一つのことは、入力されたが、だった場合はI / Oがブロックされて、とてもこのスレッドがブロックされています。

I / Oをノンブロッキング、ないShadeng I / O文の終了が、フォローという文を実行します。

非ブロッキングはまだ問題を解決することができるのだろうか?例えば、赤、ビジネス、実装プロセスの実装は、この時点では剛のI / O完了コールバックは、どのように行うには?

イベントメカニズム、イベントループは、新しいユーザの要求、または古いユーザーI / O完了するかどうか、イベントに参加するすべての方法は、スケジュールされるのを待って、イベントループになります。

2. HTTPモジュール

2.1実施例REQ、RES
1//require表示引包,引包就是引用自己的一个特殊功能
2var http = require("http");

3//创建服务器,参数是一个回调函数,表示如果有请求进来,要做什么
4var server = http.createServer(function(req,res){
5   //req表示请求,request;  res表示响应,response
6   //设置HTTP头部,状态码是200,文件类型是html,字符集是utf8
7   res.writeHead(200,{"Content-type":"text/html;charset=UTF-8"});
8   res.end("哈哈哈哈,我买了一个iPhone" + (1+2+3) + "s");
9});
10
11//运行服务器,监听3000端口(端口号可以任改)
server.listen(3000,"127.0.0.1");

REQ要求、要求、RESが応答を示し、応答

変更したい場合、あなたは、再び現在実行しているサーバー、ノードを中断したジョブを更新する必要があります。

Ctrl + Cは、保留中のサーバープログラムを中断することができます。

あなたは私たちの地元の書き込みというJSを見つけるだろう、殺害を直接実行するためにブラウザにドラッグすることはできませんが、ノードで、私たちのいずれかのノードで実行できるファイルをJS。言い換えれば、ノードは、JSの実行環境です。

1//这个案例简单讲解http模块
2//引用模块
3var http = require("http");
4
5//创建一个服务器,回调函数表示接收到请求之后做的事情
6var server = http.createServer(function(req,res){
7   //req参数表示请求,res表示响应
8   console.log("服务器接收到了请求" + req.url);
9   res.end();
10});
11//监听端口
server.listen(3000,"127.0.0.1");
2.2 req.url

私たちは今、REQ内で使用することができ、物事を見てください。

キーはreq.url属性は、ユーザーのリクエストのURLアドレスを示しています。すべてのルーティング設計は、req.urlによって実現されています。

私たちはより多くのURLを取得しますが、このURLを認識していない懸念しています。

识别URL,用到两个新模块,第一个就是url模块,第二个就是querystring模块

2.3 res.end(),write(),writeHead()
2.4 总结

response得先writeHead()才可以写其他语句。

res.writeHead(200,{"Content-Type":"text/html;charset=UTF8"});

3. querystring 模块

querystring.decode() == querystring.parse()

新增于: v0.1.99

querystring.decode() 函数是 querystring.parse() 的别名。

querystring.encode() == querystring.stringify()

新增于: v0.1.99

querystring.encode() 函数是 querystring.stringify() 的别名。

var querystring=require("querystring");

var string1=querystring.parse('foo=bar&abc=xyz&abc=123');
console.log(string1)

var string2=querystring.decode('foo=bar&abc=xyz&abc=123');
console.log(string2)
//[Object: null prototype] { foo: 'bar', abc: [ 'xyz', '123' ] }
3.1 querystring.parse(str[, sep[, eq[, options]]])

querystring.parse() 方法将 URL 查询字符串 str 解析为键值对的集合。

例如,查询字符串 'foo=bar&abc=xyz&abc=123' 被解析为:

{
  foo: 'bar',
  abc: ['xyz', '123']
}

querystring.parse() 方法返回的对象不是原型继承自 JavaScript Object。 这意味着典型的 Object 方法如 obj.toString()obj.hasOwnProperty() 等都没有定义并且不起作用。

3.2 querystring.stringify(obj[, sep[, eq[, options]]])

querystring.stringify() 方法通过迭代对象的自身属性从给定的 obj 生成 URL 查询字符串。

querystring.stringify({ foo: 'bar', baz: ['qux', 'quux'], corge: '' });
// 返回 'foo=bar&baz=qux&baz=quux&corge='

querystring.stringify({ foo: 'bar', baz: 'qux' }, ';', ':');
// 返回 'foo:bar;baz:qux'
3.3总结:

parse是相当于编译成json,stringfy相当于是把json变成了字符串。

4.url模块

4.1 网址构成

URL 'http://user:[email protected]:8080/p/a/t/h?query=string#hash'

画像-20191004135129123

Url {
  protocol: 'http:',    // 指的是底层使用的协议是http
  slashes: true,        // 说明是否有协议的双斜线
  auth: null,
  host: 'imooc.com',    // 指的是http协议的一个Ip地址或者域名
  port: null,           // 端口,默认是 80 端口,如果使用了别的端口就必须指明
  hostname: 'imooc.com', // 主机名
  hash: null,            // hash值,通常对应页面上某个锚点,加#号之后将页面滚动到当前位置的
  search: null,          // 查询字符串参数
  query: null,           // 发送给http服务器的数据,通常是被等号分隔开的键值对称之为参数串
  pathname: '/course/list', // 访问资源路径名
  path: '/course/list',   // 路径
  href: 'http://imooc.com/course/list' // 没被解析的完整的超链接
}
4.2 url.parse()

使用url.parse()方法来将url解析成一个对象

url.parse()后面加一个true,可以将query参数解析成参数对象

let obj = url.parse(str,true);
var server = http.createServer(function (req, res) {
    console.log("服务器收到请求" + req.url);
    var querystring1=url.parse(req.url,true).query;
    res.end(querystring1.name+"+"+querystring1.age);
});
4.3 pathname

得到路由路径

//得到用户的路径
    var pathname = url.parse(req.url).pathname;
    //默认首页
    if(pathname == "/"){
        pathname = "index.html";
    }
    //拓展名
    var extname = path.extname(pathname);

5.fs模块

5.1 fs.readFile(),fs.readFileSync()

读文件

var fs = require("fs");

res.writeHead(200,{"Content-Type":"text/html;charset=UTF8"});

    //两个参数,第一个是完整路径,当前目录写./
    //第二个参数,就是回调函数,表示文件读取成功之后,做的事情

    fs.readFile("./test/1.txt",function(err,data){
        if(err){
            throw err;
        }
        console.log(userid + "文件读取完毕");
        res.end(data);
    });
5.2 处理图标路由的输出
//不处理小图标
    if(req.url == "/favicon.ico"){
        return;
    }
5.3 mkdir(),mkdirSync()

异步地创建目录。 除了可能的异常,完成回调没有其他参数。

可选的 options 参数可以是指定模式(权限和粘滞位)的整数,也可以是具有 mode 属性和 recursive 属性(指示是否应创建父文件夹)的对象。

// 创建 /tmp/a/apple 目录,无论是否存在 /tmp 和 /tmp/a 目录。
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
  if (err) throw err;
});
5.4 fs.stat类

stats.isDirectory()

如果 fs.Stats 对象描述文件系统目录,则返回 true

stats.isFile()

如果 fs.Stats 对象描述常规文件,则返回 true

fs.stat("./album/" + thefilename , function(err,stats){
                //如果他是一个文件夹,那么输出它:
                if(stats.isDirectory()){
                    wenjianjia.push(thefilename);
                }
5.5 fs.readdir(path[, options], callback)

读取目录的内容。 回调有两个参数 (err, files),其中 files 是目录中的文件名的数组(不包括 '.''..')。

可选的 options 参数可以是指定编码的字符串,也可以是具有 encoding 属性的对象,该属性指定用于传给回调的文件名的字符编码。 如果 encoding 设置为 'buffer',则返回的文件名是 Buffer 对象。

如果 options.withFileTypes 设置为 true,则 files 数组将包含 [fs.Dirent] 对象。

path <string> | <Buffer> | <URL>
options <string> | <Object>

    encoding <string> 默认值: 'utf8'。
    withFileTypes <boolean> 默认值: false。
callback <Function>

    err <Error>
    files <string[]> | <Buffer[]> | <fs.Dirent[]>
5.6 异步编程思想——循环语句,异步语句

错误输出:循环语句嵌套异步,输出出错

var server = http.createServer(function(req,res){
    //不处理小图标
    if(req.url == "/favicon.ico"){
        return;
    }
    //存储所有的文件夹
    var wenjianjia = [];
    //stat检测状态
    fs.readdir("./album",function(err,files){
        //files是个文件名的数组,并不是文件的数组,表示./album这个文件夹中的所有东西
        //包括文件、文件夹
        for(var i = 0 ; i < files.length ;i++){
            var thefilename = files[i];
            //又要进行一次检测
            fs.stat("./album/" + thefilename , function(err,stats){
                //如果他是一个文件夹,那么输出它:
                if(stats.isDirectory()){
                    wenjianjia.push(thefilename);
                }
                console.log(wenjianjia);
            });
        }
    });
});
5.7 把异步变成同步

使用迭代器iterator()

迭代器就是强行把异步的函数,变成同步的函数

var http = require("http");
var fs = require("fs");

var server = http.createServer(function(req,res){
    //不处理收藏夹小图标
    if(req.url == "/favicon.ico"){
        return;
    }
    //遍历album里面的所有文件、文件夹
    fs.readdir("./album/",function(err,files){
        //files : ["0.jpg","1.jpg" ……,"aaa","bbb"];
        //files是一个存放文件(夹)名的数组
        //存放文件夹的数组
        var wenjianjia = [];
        //迭代器就是强行把异步的函数,变成同步的函数
        //1做完了,再做2;2做完了,再做3
        (function iterator(i){
            //遍历结束
            if(i == files.length){
                console.log(wenjianjia);
                return;
            }
            fs.stat("./album/" + files[i],function(err,stats){
                //检测成功之后做的事情
                if(stats.isDirectory()){
                    //如果是文件夹,那么放入数组。不是,什么也不做。
                    wenjianjia.push(files[i]);
                }
                iterator(i+1);
            });
        })(0);
    });
    res.end();
});

server.listen(3000,"127.0.0.1");

6. path模块

path 模块提供用于处理文件路径和目录路径的实用工具。

6.1 dirname(path)

path.dirname()この方法は、返しpathのUnixに似たディレクトリの名前、dirnameコマンドを。

path.dirname('/foo/bar/baz/asdf/quux');
// 返回: '/foo/bar/baz/asdf'
6.2 path.extname(パス)

path.extname()この方法は返しpath延長、最後から出現.まで(ピリオド)文字path、最終的な終了の文字列部分を。場合はpath、最後の部分がない.場合、またはpath最初の文字に加えて、ベース名ではありません.空の文字列が返されます。

path.extname('index.html');
// 返回: '.html'

path.extname('index.coffee.md');
// 返回: '.md'

path.extname('index.');
// 返回: '.'

path.extname('index');
// 返回: ''

path.extname('.index');
// 返回: ''

path.extname('.index.md');
// 返回: '.md'
6.3 path.join([...パス])

path.join()すべての指定された区切り文字として使用されるプラットフォーム固有のデリミタの方法pathパスセグメントが互いに接続され、正規化をもたらします。

長さがゼロのpathセグメントは無視されます。パスである場合、文字列の連結長さゼロのストリングが返され'.'、現在の作業ディレクトリを示します。

path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// 返回: '/foo/bar/baz/asdf'

path.join('foo', {}, 'bar');
// 抛出 'TypeError: Path must be a string. Received {}'
6.4 path.parse(パス)

path.parse()この方法は、その特性が表すオブジェクト戻りpath重要な要素。

path.parse('/home/user/dir/file.txt');
// 返回:
// { root: '/',
//   dir: '/home/user/dir',
//   base: 'file.txt',
//   ext: '.txt',
//   name: 'file' }
6.5静的リソースファイルの管理
var http = require("http");
var url = require("url");
var fs = require("fs");
var path = require("path");

http.createServer(function(req,res){
    //得到用户的路径
    var pathname = url.parse(req.url).pathname;
    //默认首页
    if(pathname == "/"){
        pathname = "index.html";
    }
    //拓展名
    var extname = path.extname(pathname);

    //真的读取这个文件
    fs.readFile("./static/" + pathname,function(err,data){
        if(err){
            //如果此文件不存在,就应该用404返回
            fs.readFile("./static/404.html",function(err,data){
                res.writeHead(404,{"Content-type":"text/html;charset=UTF8"});
                res.end(data);
            });
            return;
        };
        //MIME类型,就是
        //网页文件:  text/html
        //jpg文件 :   image/jpg
        var mime = getMime(extname);
        res.writeHead(200,{"Content-type":mime});
        res.end(data);
    });

}).listen(3000,"127.0.0.1");

function getMime(extname){
    switch(extname){
        case ".html" :
            return "text/html";
            break;
        case ".jpg" : 
            return "image/jpg";
            break;
        case ".css":
            return "text/css";
            break;
    }
}

2019年10月4日午後04時五十六分17秒

おすすめ

転載: www.cnblogs.com/oneapple/p/12050722.html