• 进击Node.js基础(一)


    一.NodeJS基本介绍

    1.Node-Webkit、appjs:允许开发者使用Web技术,html/css来开发跨平台的桌面应用程序,能兼容mac、Linux、Windows
    2.Jade:和NodeJS组合使用,可以高效的管理后台html模板
    3.Ghost:是一个强大且体验超好的开源博客程序
    4.Grunt:是javascript跑各种任务的运行工具,通过集成各种插件来完成比如样式编译、脚本检查、脚本压缩合并、自动化测试、Shell脚本运行、文档生成,甚至是图片处理等等各种各样的任务。
    5.gulp:针对grunt的复杂配置有了更简洁高效的组织方式
    6.Express.js:基于Node.js 平台,快速、开放、极简的 web 开发框架
    7.Nodecast:先是在PC端运行它,然后启动移动设备,选择一个支持Nodecast的应用程序,然后就可以把移动广播中的内容映射到电脑上,等于把电脑当一个流媒体来使用
    8.Log.io:让你在浏览器里面可以实时地监控项目日志
    9.PDFKit:用来生成PDF文档
    10.Haroopad:是一个Linux上的markdown编辑器
    11.NoduinoWeb:硬件黑客希望通过Noduino Web页面来控制开源硬件,从而将软件和硬件很好的结合起来
    12.NodeOS:是一款基于Node.js的开发的友好的操作系统

    二.学习NodeJS推荐四个网站
    1.nodejs.org,官网
    2.www.npmjs.com,模块社区搜索对应的模块,参加别人代码是如何组织的
    3.github.com,阅读优秀的源码
    4.stackoverflow.com,技术问答社区

    三.Node.js的版本
    偶数位为稳定的版本 -0.6.x,-0.8.x,-0.10.x
    奇数位为非稳定的版本 -0.7.x,-0.9.x,-0.11.x

    四.Windows上安装git bash
    一路下一步安装完毕

    五.安装nodejs
    https://nodejs.org/下载nodejs安装成功后,会自动在环境变量的Path中添加nodejs的安装路径

    运行环境:如下是在Chrome浏览器上运行js和在Node.js中运行js

    第一个实例:server.js

    const http = require('http');
    
    const hostname = '127.0.0.1';
    const port = 3000;
    
    const server = http.createServer((req, res) => {
      res.statusCode = 200;
      res.setHeader('Content-Type', 'text/plain');
      res.end('Hello Node.js
    ');
    });
    
    server.listen(port, hostname, () => {
      console.log(`Server running at http://${hostname}:${port}/`);
    });

      在git bash上进入server.js所在的目录,输入node server.js

      然后在浏览器中输入:http://127.0.0.1:3000/,运行效果如下:

    六.模块与包管理工具

     

    实例:

    teacher.js

    function add(teacher) {
        console.log('Add Teacher:' + teacher)
    }
    
    exports.add = add

    student.js

    function add(student) {
        console.log('Add Student:' + student)
    }
    
    exports.add = add

    klass.js

    var student = require('./student.js')
    var teacher = require('./teacher.js')
    
    function add(teacherName, students) {
        teacher.add(teacherName)
    
        students.forEach(function(item, index) {
            student.add(item)
        })
    }
    
    //传统的模块实例,exports是module的一个辅助方法,推荐这种方式
    exports.add = add
    //实例成为特殊的模块类型,真实存在的东西,返回调用者exports挂载的属性和方法赋给module.exports
    //如果module.exports存在属性和方法,则被忽略
    //module.exports = add

    index.js

    var klass = require('./klass')
    
    klass.add('Scott', ['白富美','高富帅'])
    
    exports.add = function(klasses) {
        klasses.forEach(function(item, index) {
            var _klass = item
            var teacherName = item.teacherName
            var students = item.students
            klass.add(teacherName, students)
        })
    }

    七.Node.js API
      分化为node.js、io.js两个阵营

    八.URL网址解析的好帮手

    url.parse('http://imooc.com/course/list')
    Url {
      protocol: 'http:',
      slashes: true,
      auth: null,
      host: 'imooc.com',
      port: null,
      hostname: 'imooc.com',
      hash: null,
      search: null,
      query: null,
      pathname: '/course/list',
      path: '/course/list',
      href: 'http://imooc.com/course/list' }
    > url.parse('http://imooc.com:8080/course/list?from=scott&course=node#floor!')
    Url {
      protocol: 'http:',
      slashes: true,
      auth: null,
      host: 'imooc.com:8080',
      port: '8080',
      hostname: 'imooc.com',
      hash: '#floor!',
      search: '?from=scott&course=node',
      query: 'from=scott&course=node',
      pathname: '/course/list',
      path: '/course/list?from=scott&course=node',
      href: 'http://imooc.com:8080/course/list?from=scott&course=node#floor!' }
    > url.format({
    ...   protocol: 'http:',
    ...   slashes: true,
    ...   auth: null,
    ...   host: 'imooc.com:8080',
    ...   port: '8080',
    ...   hostname: 'imooc.com',
    ...   hash: '#floor!',
    ...   search: '?from=scott&course=node',
    ...   query: 'from=scott&course=node',
    ...   pathname: '/course/list',
    ...   path: '/course/list?from=scott&course=node',
    ...   href: 'http://imooc.com:8080/course/list?from=scott&course=node#floor!' }
    ... )
    'http://imooc.com:8080/course/list?from=scott&course=node#floor!'
    > url.resolve('http://imooc.com/','/course/list')
    'http://imooc.com/course/list'
    > url.parse('http://imooc.com:8080/course/list?from=scott&course=node#floor1')
    Url {
      protocol: 'http:',
      slashes: true,
      auth: null,
      host: 'imooc.com:8080',
      port: '8080',
      hostname: 'imooc.com',
      hash: '#floor1',
      search: '?from=scott&course=node',
      query: 'from=scott&course=node',
      pathname: '/course/list',
      path: '/course/list?from=scott&course=node',
      href: 'http://imooc.com:8080/course/list?from=scott&course=node#floor1' }
    > url.parse('http://imooc.com:8080/course/list?from=scott&course=node#floor1', t
    rue)
    Url {
      protocol: 'http:',
      slashes: true,
      auth: null,
      host: 'imooc.com:8080',
      port: '8080',
      hostname: 'imooc.com',
      hash: '#floor1',
      search: '?from=scott&course=node',
      query: { from: 'scott', course: 'node' },
      pathname: '/course/list',
      path: '/course/list?from=scott&course=node',
      href: 'http://imooc.com:8080/course/list?from=scott&course=node#floor1' }
    > url.parse('//imooc.com/course/list',true)
    Url {
      protocol: null,
      slashes: null,
      auth: null,
      host: null,
      port: null,
      hostname: null,
      hash: null,
      search: null,
      query: {},
      pathname: '//imooc.com/course/list',
      path: '//imooc.com/course/list',
      href: '//imooc.com/course/list' }
    > url.parse('//imooc.com/course/list',true,true)
    Url {
      protocol: null,
      slashes: true,
      auth: null,
      host: 'imooc.com',
      port: null,
      hostname: 'imooc.com',
      hash: null,
      search: null,
      query: {},
      pathname: '/course/list',
      path: '/course/list',
      href: '//imooc.com/course/list' }
    >

    九.QueryString参数处理小利器

    > querystring.stringify({name:'scott', course:['jade','node'], from:''})
    'name=scott&course=jade&course=node&from='
    > querystring.stringify({name:'scott', course:['jade','node'], from:''}, ',')
    'name=scott,course=jade,course=node,from='
    > querystring.stringify({name:'scott', course:['jade','node'], from:''}, ',', ':')
    'name:scott,course:jade,course:node,from:'
    > querystring.parse('name=scott&course=jade&course=node&from=')
    { name: 'scott', course: [ 'jade', 'node' ], from: '' }
    > querystring.parse('name=scott,course=jade,course=node,from=', ',')
    { name: 'scott', course: [ 'jade', 'node' ], from: '' }
    > querystring.parse('name=scott,course=jade,course=node,from=')
    { name: 'scott,course=jade,course=node,from=' }
    > querystring.parse('name=scott,course=jade,course=node,from=', ',', '=')
    { name: 'scott', course: [ 'jade', 'node' ], from: '' }
    
    > querystring.escape('<哈哈>')
    '%3C%E5%93%88%E5%93%88%3E'
    > querystring.unescape('%3C%E5%93%88%E5%93%88%3E')
    '<哈哈>'

    十.HTTP知识先填坑
      http客户端发起请求,创建端口
      http服务器在端口监听客户端请求
      http服务器向客户端返回状态和内容

      当输入网址回车,页面就出来了,但计算机和浏览器做了许许多多的事情:
    1.Chrome搜索自身的DNS缓存
      浏览器上输入:chrome://net-internals/#dns,就可以查看曾经浏览过的网站的DNS缓存记录

    2.搜索操作系统自身的DNS缓存(浏览器没有找到缓存或缓存已经失效)

      如浏览器没有找到缓存或已失效,则搜索操作系统自身的DNS缓存,如找到且没有过期,则会停止搜索,解析到此结束

    3.读取本地的HOST文件
    如操作系统的dns缓存也没有找到,则会去读本地的host文件,如windows是在C:WindowsSystem32driversetc目录下。
    4.浏览器发起一个DNS的一个系统调用
     如果在本地的host文件中也没有找到对应的配置项,浏览器就会发起一个DNS的一个系统调用,向本地主控dns服务器(是你的宽带运营商提供的)发起一个域名解析请
    求,运营商的dns服务器具体会做如下事情:
     a.宽带运营商服务器查看本身缓存
     b.运营商服务器发起一个迭代dns解析的请求(实际步骤可能比这复杂)
      嘿,哥们imooc.com的域名地址是多少?
    我只知道com域的项级域的ip地址
      运营商主控dns服务器就找到com域的服务器,向项级域的ip地址服务器询问imooc.com的域名地址是多少
      我只知道imooc.com域的IP地址
      运营商主控dns服务器就找到imooc.com域的dns服务器,这个一般是域名的注册商提供的,然后问它imooc.com域的ip地址是多少
      imooc.com域的dns服务器一查,查然在我这,然后把它查到的结果发送给运营商的dns服务器
      运营商服务器把结果返回操作系统内核同时缓存起来
      操作系统内核把结果返回浏览器
      最终浏览器拿到了www.imooc.com对应的IP地址
    5.浏览器获得域名对应的IP地址后,发起HTTP“三次握手”
      浏览器会以一个随机端口向服务器的web程序(如http的80端口)发起TCP连接请求,这个连接请求通过层层路由设备到达服务器后进入到网卡,然后进入到内核的TCP/IP协议栈,还有可能要经过防火墙的过滤,最终到达web服务端,然后建立起tcp/ip的连接。
      “三次握手”过程:
      a.客户端对服务器说:哥们,能听到我说话吗?唠唠呗
      b.服务器就对客户端说:兄弟,我能听到你说话,咱唠唠
      c.客户端再对服务器说:好的哥们,咱俩开唠吧
    6.TCP/IP连接建立起来后,浏览器就可以向服务器发送HTTP请求了,使用了比如说,用HTTP的GET方法请求一个根域里的一个域名,协议可以采HTTP1.0的一个协议
    7.服务器端接受到了这个请求,根据路径参数,经过后端的一些处理之后,把处理后的一个结果的数据返回给浏览器,如果是慕课网的页面就会把完整的HTML页面代码返
    回给浏览器
    8.浏览器拿到了慕课网的完整的HTML页面代码,在解析和渲染这个页面的时候,里面的JS、CSS、图片静态资源,他们同样也是一个个HTTP请求都需要经过上面的主要的
    七个步骤
    9.浏览器根据拿到的资源对页面进行渲染,最终把一个完整的页面呈现给了用户

    十一.HTTP请求的流程拆分开,拆分成请求和响应,无论请求还是响应,都会发送http头和正文信息
      HTTP头发送的是一些附加的信息:内容类型、服务器发送响应的日期、HTTP状态码,正文就是用户提交的表单数据。

    十二.Chrome浏览器F12查看HTTP请求
    1.Timing:图形化显示这个请求加裁过程中每个阶段所要耗费的时间
      a.Stalled:浏览器要发出这个请求到这个请求可以发出的这个等待时间,一般是代理协商、配置的pk脚本、等待可复用的TCP连接释放的时间,不包含查询和建立TCP连
    接的时间
      b.Proxy negotiation:代理协商的时间
      c.Reuqest/Response
        Request sent:请求的第一个字节发出以前到最后一个字节发出后的时间,可以理解为请求时间或上传时间
        Waiting(TTFB):请求发出以后到收到响应的第一个字节所花费的时间,这个包括整个数据在各个路由中贯穿中所延迟的时间,以及服务器端要响应这个请求所做的后台的一些处理,可以看到这个所耗费的时间最长,尤其是我们有大文件上传时会更慢
        Content Download:收到响应的第一个字节开始,到接收完最后一个字节所花费的时间,也就是下载时间
    通过分析这个Timing,或者根据之前页面历史上数据的对比,就可以找到一些页面慢,以及慢的瓶颈在哪。
    2.Headers
      1)和请求有关
      a.Remote Address:远端服务器的IP地址
      b.Request URL:请求地址
      c.Request Method:请求方法
      d.Request Headers:请求头
      2)和响应有关
      a.Status Code:响应状态码
      b.Response Headers:响应头

    十三.HTTP请求方法
      HTTP1.1协议中定义了八种方法(或叫动作)
      GET:获取数据
      POST:向指定的资源提交数据,如要新建一个用户、上传一个视频
      PUT:更新,向指定的资源上传一个最新内容,如更新已有用户的头像,替换一个已有的视频
      DELETE:删除,请求服务器删除我们标识的某个资源
      HEAD:和GET一样,都是向服务器发出指定资源的一个请求,只不过服务器它不传回资源的本文的部分,它的好处是不用传输全部的内容就可以获取里面的原信息或原数

      CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
      TRACE:回显服务器收到的请求,主要用于测试或诊断
      OPTIONS:允许客户端查看服务器的性能

    十四.HTTP请求的状态码
    浏览器返回给浏览器时,告之浏览器我当前的请求成功或失败的一个指示信息的状态,一般三个数字组成,第一个数字定义响应的类别。
      1XX:给示请求已经接收,继续处理
      2XX:表示成功,请求已成功的接收并处理掉了
      3XX:重定向,表示要完成这个请求必须要进行更进一步的操作
      4XX:客户端错误,请求时有误法错误或者这个请求无法实现
      5XX:服务端错误,服务器不能实现这个合法的请求
    如常见的状态码
      200:OK,说明客户端请求成功
      400:客户端请求有语法错误,服务器端不能理解
      401:请求未经过授权
      403:服务端收到这个请求,但是拒绝提供服务,可能还是没有权限等等
      404:没找到,请求资源不存在或者是你输错了URL地址
      500:服务器端发生了不可预期的错误
      503:服务器当前还不能处理当前的这个请求,可能需要过一段时间之后才能恢复正常

    十五.HTTP事件回调进阶
      HTTP模块有考虑支持很多HTTP协议的特性,这些特性在传统开发中确很难使用,比如大体积的扩编码的消息,除此之外,为了让用户可以在请求和响应中使用流的形式操作数据,
    接口从不缓存整个请求或者响应,整个HTTP API都很底层,它只处理流相关的操作以及信息解析,可以把信息解析成请求头、请求体,但并不去解析实际的请求头和请求正文里面的具体内容。
    1.HTTP概念进阶
    a.什么是回调?
      异步编程最基本的方法,需按顺序执行异步逻辑时,一般采用后续传递的方法。也就是将后续逻辑封装在回调函数中做为起始函数的参数层层嵌套,通过这种方式来让程序按照我们所期望的方式走完整个流程。

    callback.js

    function learn(something) {
        console.log(something)
    }
    
    function we(callback, something) {
        something += ' is cool'
        callback(something)
    }
    
    we(learn, 'Nodejs')
    
    we(function(something) {
        console.log(something)
    }, 'Jade')

     b.什么是同步/异步?

      同步就是执行一个任务,后面一个任务等待前一个任务结束。
      每个任务有一个或多个回调函数

    async.js

    var c = 0
    
    function printIt() {
        console.log(c)
    }
    
    function plus() {
        setTimeout(function() {
            c += 1
        }, 1000)
    }
    
    plus()
    printIt()

    async2.js

    var c = 0
    
    function printIt() {
        console.log(c)
    }
    
    function plus(callback) {
        setTimeout(function() {
            c += 1
            callback()
        }, 1000)
    }
    
    plus(printIt)

    c.什么是I/O?
      磁盘的写入和读出,为文件系统、数据库资料提供接口,向文件系统发送请求时,不用等到硬盘,硬盘准备好了,非阻塞接口会通知到Node
    d.什么是单线程/多线程?
      单线程代码是按顺序执行的,多线程代码
    e.什么是阻塞/非阻塞
    f.什么是事件?
      鼠标点击、拖拽窗口都是事件
    g.什么是事件驱动?

    event.js

    function clickIt(e) {
        window.alert('Button is cliecked')
    }
    
    var button = document.getElementById('#button')
    button.addEventListener('click', clickIt)

      这几行代码就能实现当按钮被点击时就能触发一个回调函数,就是这个clickIt,弹出一个框

      所有能触发事件的对象,都是Event下面的EventEmitter的实例
      为了某个事件注册函数,像这个函数不是马上执行,只有当事件发生时才会调用回调函数,这种函数执行的方式就叫做事件驱动。
    h.什么是基于事件驱动的回调?
      这种注册回调就是基于事件驱动的回调,如果这些回调和异步IO操作有关,则就可以看作是基于回调的异步IO,只不过这种回调是在Node.js里面是由事件来驱动的。
    i.什么是事件循环?
      如果有大量的异步操作,以及IO的耗时操作,甚至是一些定时器控制的延时操作,它们完成时都要去调用相应的回调函数,从而来完成一些密集的任务,而又不会阻塞整个程序执行的流程,那这个时候,这么多事件就需要一个机制来管理,这种机制就是事件循环。
      EventLoop是一个回调函数队列,当异步函数执行的时候,回调函数就会被压入到这人队列,对Node.js来说,靠一个单线程不断地查询队列中是否有事件,当它读取到一个事件时,将调用与这个事件关联的javaScript函数。
      事件循环是一个先进先出的任务队列,回调就按照它们被加入的顺序来执行。整个队列可以理解成普通函数和回调函数构成的一个完整的队列。

    十六.HTTP源码解读
    1.什么是作用域?
      作用域和调用函数访问变量的能力有关
      分:局部作用域和全局作用域

    scope.js

    var globalVariable = 'This is global variable'
    
    function globalFunction() {
        var localVariable = 'This is local variable'
    
        console.log('Visit global/local variable')
        console.log(globalVariable)
        console.log(localVariable)
    
        globalVariable = 'This is changed variable'
        console.log(globalVariable)
    
        function localFunction() {
            var innerLocalVariable = 'This is inner local variable'
    
            console.log('Visit global/local/innerLocal variable')
            console.log(globalVariable)
            console.log(localVariable)
            console.log(innerLocalVariable)
        }
    
        localFunction()
    }
    
    globalFunction()

    运行结果:


    2.什么是上下文?

    context.js

    var pet = {
        words: '...',
        speak: function() {
            console.log(this.words)
            console.log(this === pet)
        }
    }
    
    pet.speak()

    运行结果:

    context02.js

    function pet(words) {
        this.words = words
        console.log(this.words)
        console.log(this === global)
    }
    
    //这里调pet方法,调用这个方法的对象并不是pet自身,而是顶层的global对象
    pet('...')

    运行结果:

    context03.js

    function Pet(words) {
        this.words = words
        this.speak = function() {
            console.log(this.words)
            console.log(this)
        }
    }
    
    var cat = new Pet('Miao')
    
    cat.speak()

    运行结果:

    通过以上三段代码,我们来理解一下上下文:

      this关键字有关,是调当前可执行代码的引用

      在js里面,this关键字通常是指向当前函数的拥有者,通常把拥有者叫做执行上下文。
      this是JS语言的一个关键字,代表函数运行时自动生成的一个内部对象,只能在函数内部使用。
      同时,对于函数的上下文执行对象,需要依据当前的运行环境而定,因为上下文执行对象在程序运行时来确定,也可以动态去改变。
      在全局运行的上下文中,this指向的是全局对象,在函数内部,this取决于函数被调用的方式,被调用的方式主要有:
      a.作为对象的方法,pet.speak(),里面的this指向的对象就是pet这个对象
      b.直接函数调用,这时内部的this指向的是全局对象
      c.在构造函数中使用this,那这个this就指向到新构建好的对象,就是实例对象。
      JS的上下文存在一个定义时的上下文和运行时的上下文以及上下文可以改变的。
      使用call和apply可以改变上下文执行对象,可以让你在自定义上下文中执行函数,作用一样,用法有区别。call函数需要一个参数列表,apply允许传递一个参数做为数组。作用是调用一个对象的方法,利用另一个对象替换当前对象,其实就是更改对象this指向的内容。说的标准点就是,以某个方法当做指定的某个对象的方法来执行。

    call_apply.js

    var pet = {
        words: '...',
        speak: function(say) {
            console.log(say + ' ' + this.words)
        }
    }
    
    //pet.speak('Speak')  //Speak ...
    
    var dog = {
        words: 'Wang'
    }
    
    //在调某个方法时,指定dog这个对象为上下文,利用这种用法,也很方便实现继承
    pet.speak.call(dog, 'Speak') //Speak Wang

    运行结果:

    call_apply_extend.js

    function Pet(words) {
        this.words = words
        this.speak = function() {
            console.log(this.words)
        }
    }
    
    function Dog(words) {
        Pet.call(this, words)
        //Pet.apply(this, arguments)
    }
    
    var dog = new Dog('Wang')
    dog.speak()

    运行结果:

    3.HTTP源码解读

        带着问题看代码。

    十七.HTTP性能小测试
    1.Apache ab
      在命行里输入:ab -n1000 -c10 http://localhost:3000/
      -n1000:总的请求数是1000,默认是1
      -c10:并发数是10,默认是1
      -t:用来测试进行的总时间
      -p:post时的数据文件
      -w:以html表格格式输出结果
    2.ab -n1000 -c10 http://www.imooc.com/
      慕课网性能小测试

    十八.HTTP爬虫
      借助HTTP API,使用cheerio抓取网页数据,npm install cheerio
    imooc-crawler.js

    var http = require('http')
    var url = 'http://www.imooc.com/learn/348'
    
    http.get(url, function(res) {
        var html = ''
        res.on('data', function(data) {
            html += data
        })
    
        res.on('end', function() {
            console.log(html)
        })
    }).on('error', function() {
        console.log('获取课程数据出错!')
    })

    运行结果:

    crawler.js

    var http = require('http')
    var cheerio = require('cheerio')
    var url = 'http://www.imooc.com/learn/348'
    
    function filterChapters(html) {
        var $ = cheerio.load(html)
    
        var chapters = $('.learnchapter')
        var courseData = []
    
        chapters.each(function(item) {
            var chapter = $(this)
            var charterTitle = chapter.find('strong').text()
            var videos = chapter.find('.video').children('li')
            var chapterData = {
                chapterTitle: chapterTitle,
                videos : []
            }
    
            videos.each(function(item) {
                var video = $(this).find('.studyvideo')
                var videoTitle = video.text()
                var id = video.attr('href').split('video/')[1]
    
                chapterData.videos.push({
                    title: videoTitle,
                    id: id
                })
            })
    
            courseData.push(chapterData)
        })
        return courseData;
    }
    
    function printCourseInfo(courseData) {
        courseData.forEach(function(item) {
            var chapterTitle = item.chapterTitle
    
            console.log(charterTitle + '
    ')
    
            item.videos.forEach(function(video) {
                console.log(' [' + video.id + ']' + video.title  + '
    ')
            })
        })
    }
    
    http.get(url, function(res) {
        var html = ''
        res.on('data', function(data) {
            html += data
        })
    
        res.on('end', function() {
            var courseData = filterChapters(html)
            printCourseInfo(courseData)
        })
    }).on('error', function() {
        console.log('获取课程数据出错!')
    })

    运行结果:

    十九.事件模块小插曲

      event emit可以为某个事件添加最多10个监听函数。
      官方建议对一个事件不要设置超过10个监听器,太多会导致内存泄露。

    events.js

    var EventEmitter = require('events').EventEmitter
    
    var life = new EventEmitter()
    life.setMaxListeners(11)
    
    //也可用addEventListener
    
    function water(who) {
        console.log('给 ' + who + ' 倒水')
    }
    
    life.on('求安慰', water)
    
    life.on('求安慰', function(who) {
        console.log('给 ' + who + ' 揉肩')
    })
    
    life.on('求安慰', function(who) {
        console.log('给 ' + who + ' 做饭')
    })
    
    life.on('求安慰', function(who) {
        console.log('给 ' + who + ' 洗衣服')
    })
    
    life.on('求安慰', function(who) {
        console.log('给 ' + who + ' ...5')
    })
    
    life.on('求安慰', function(who) {
        console.log('给 ' + who + ' ...6')
    })
    life.on('求安慰', function(who) {
        console.log('给 ' + who + ' ...7')
    })
    life.on('求安慰', function(who) {
        console.log('给 ' + who + ' ...8')
    })
    life.on('求安慰', function(who) {
        console.log('给 ' + who + ' ...9')
    })
    life.on('求安慰', function(who) {
        console.log('给 ' + who + ' ...10')
    })
    life.on('求安慰', function(who) {
        console.log('给 ' + who + ' 你想累死我啊')
    })
    
    life.on('求溺爱', function(who) {
        console.log('给 ' + who + ' 买衣服')
    })
    life.on('求溺爱', function(who) {
        console.log('给 ' + who + ' 交工资')
    })
    
    life.removeListener('求安慰', water)
    //life.removeAllListeners()
    life.removeAllListeners('求安慰')
    
    var hasConfortListener = life.emit('求安慰', '汉子')
    var hasLovedListener = life.emit('求溺爱', '妹子')
    var hasPlayedListener = life.emit('求玩坏', '妹子和汉子')
    
    console.log(life.listeners('求安慰').length)
    //console.log(EventEmitter.listenerCount(life, '求安慰'))
    console.log(life.listeners('求溺爱').length)
    
    console.log(hasConfortListener) //true
    console.log(hasLovedListener) //true
    console.log(hasPlayedListener) //false

    运行结果:

    二十.Node.js request方法
      HTTP get/request
      get是对request一个封装,get能做的事,request都能做。
      http.request(options[,callback])
      host,path,hostname,headers,port,auth,localAddress,agent,socketPath,keepAlive,method,keepAliveMsecs

     comment.js

    var http = require('http')
    var querystring = require('querystring')
    
    var postData = querystring.stringify({
        'content': '入门值得学',
        'cid': 28127
    })
    
    var options = {
        hostname: 'www.imooc.com',
        port: 80,
        path: '/course/docomment',
        method: 'POST',
        headers : {
            'Accept':'application/json, text/javascript, */*; q=0.01',
            'Accept-Encoding':'gzip, deflate, br',
            'Accept-Language':'zh-CN,zh;q=0.8',
            'Connection':'keep-alive',
            'Content-Length':postData.length,
            'Cookie':'imooc_uuid=8875f7de-e6a9-455a-8470-aac8e6c20484; imooc_isnew_ct=1502349861; PHPSESSID=547ntneegkk456214a3eiso846; loginstate=1; apsid=Y0YmZkYjg5YmU3OTMzZjI5Njg2YTE4ODcxMzU1ZTMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjc0MjIyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiaWppYW4wMzA2QDEyNi5jb20AAAAAAAAAAAAAAAAAADBmMTk2MTlkNGM3ZDJiMjI2NDc4ODJiOTRiZWMyZWEyjXDgWsvtoFY%3DN2; IMCDNS=0; Hm_lvt_f0cfcccd7b1393990c78efdeebff3968=1524151421,1524375330,1524657829,1524667446; Hm_lpvt_f0cfcccd7b1393990c78efdeebff3968=1525408676; imooc_isnew=2; cvde=5ad894ba8e870-239',
            'Host':'www.imooc.com',
            'Origin':'https://www.imooc.com',
            'Referer':'https://www.imooc.com/u/274222',
            'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36',
            'X-Requested-With':'XMLHttpRequest'
        }
    }
    
    var req = http.request(options, function(res) {
        console.log('Status:' + res.statusCode)
        console.log('headers:' + JSON.stringify(res.headers))
    
        res.on('data', function(chunk) {
            console.log(Buffer.isBuffer(chunk))
            console.log(typeof chunk)
        })
    
        res.on('end', function() {
            console.log('评论完毕!')
        })
    })
    
    req.on('error', function(e) {
        console.log('Error:' + e.message)
    })
    
    req.write(postData)
    req.end()

    运行结果:

    刷新www.imooc.com/comment/348,就能看到有刚通过代码进行的评论。

    学习视频《进击Node.js基础(一)

  • 相关阅读:
    虚树
    最小树形图
    分块
    斜率优化
    单调队列优化DP
    树套树
    2-SAT
    莫队
    单调队列
    单调栈
  • 原文地址:https://www.cnblogs.com/flyingeagle/p/8969733.html
Copyright © 2020-2023  润新知