nodejs學習(imooc課程筆記, 主講人Scott)

課程地址:javascript

http://www.javashuo.com/tag/進擊Node.js基礎(一)css

進擊Node.js基礎(二)html

1. nodejs建立服務器java

var http = require('http');        //加載http模塊

//請求進來時, 告訴服務器作什麼, 因而給createServer傳遞一個匿名回調函數. 
//兩個參數, 前面是請求體, 後面是響應體. 請求體用來獲取請求相應信息,好比請求ip地址,請求的類型get/post,res用來返回響應
http.createServer(function(req, res) {
    res.writeHead(200, {'Content-Type': 'text/palin'});
    res.end('Hello World\n');
}).listen(1337, '127.0.0.1');        //經過listen使服務器在1337端口監聽請求
console.log('Server running at https://127.0.0.1:1337/');

2. nodejs安裝:node

一開始直接使用sudo apt-get install node後, 安裝好的node不能啓動且node -v也沒有輸出. node.js的版本號是v0.10.25.可是用npm安裝一些包時候卻說node版本不夠, 沒搞明白node和nodejs區別在哪裏.linux

因而卸載掉從nodejs.org上下了新版, 是node v6.10.0. 解壓後, 直接在那個目錄下能夠啓動node, 在網上查了使用了一個連接, 分別把node 和 npm設置了全局:數據庫

sudo ln -s /media/hao/3b6b3418-c087-4836-a75d-6d7a6023e495/Programs/node-v6.10.0-linux-x64/bin/node /usr/sbin/node
sudo ln -s /media/hao/3b6b3418-c087-4836-a75d-6d7a6023e495/Programs/node-v6.10.0-linux-x64/bin/npm /usr/sbin/npm

能夠用了.npm

關於nodejs和node版本的區別,參考這個帖子吧: nodejs各版本的區別api

 

3. 模塊: 從這裏開始都是慕課網老師Scott進擊NodeJS基礎(一)(二)課程的筆記數組

  • 建立模塊
    teacher.js
  • 導出模塊
    exports.add = function(){ }
  • 加載模塊
    var teacher = require('./teacher.js')
  • 使用模塊
    teacher.add('Scott')

     

  

4. nodejs中一些api

  1. url:
    1. url.parse
    2. url.format:
    3. url.resolve

  2. querystring

 

  

5. 用nodejs作的一個爬蟲:

var http = require('http')
var cheerio = require('cheerio')        //npm install cheerio
var url = 'http://www.imooc.com/learn/348'

function filterChapters(html){
    var $ = cheerio.load(html)
    var chapters = $('.chapter')
    // [{
    //     chapterTitle: '',
    //     videos: [
    //         title:'',
    //         id: ''
    //     ]
    // }]
    var courseData = []
    chapters.each(function(item){
        var chapter = $(this)
        var chapterTitle = chapter.find('strong').text().trim('\n').split('\n')[0]
        var videos = chapter.find('.video').children('li')
        var chapterData = {
            chapterTitle: chapterTitle,
            videos: []
        }
        videos.each(function(item){
            var video = $(this).find(".J-media-item")
            var videoTitle = video.text().split(/\s+/).slice(1,-2).join(' ')
            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(chapterTitle + '\n')

        item.videos.forEach(function(video){
            console.log('   [' + video.id + ']' + video.title + '\n')
        })
    })
}
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('獲取課程數據錯誤')
})

 

6. 事件監聽的一個小例子 

var EventEmitter = require('events').EventEmitter
var life = new EventEmitter()

//addEventListener

life.setMaxListeners(6)     //設置事件最大監聽數 默認爲10. 超出這個數目會報警告

life.on('求安慰', function(who){
    console.log('給 ' + who + ' 倒水')
})

life.on('求安慰', function(who){
    console.log('給 ' + who + ' ...1')
})

life.on('求安慰', function(who){
    console.log('給 ' + who + ' ...2')
})

life.on('求安慰', function(who){
    console.log('給 ' + who + ' ...3')
})

life.on('求安慰', function(who){
    console.log('給 ' + who + ' ...4')
})

life.on('求安慰', function(who){
    console.log('給 ' + who + ' ...5')
})

life.on('求安慰', function(who){
    console.log('給 ' + who + ' ...6')
})


var hasBeenListener = life.emit('求安慰', '槓子')      //會返回值, 看是否被監聽過

//要移除函數, 不可以使用匿名函數, 只能移除具名函數

console.log(life.listeners('求安慰').length)   //查詢監聽事件數
console.log(EventEmitter.listenerCount(life, '求安慰'))

life.removeAllListeners('求安慰')
life.emit('求安慰','gangzi')

 7. Promise.js  imooc

<!DOCTYPE html>
<html>
<head>
    <title>Promise animation</title>
    <style type="text/css">
        .ball{
            width: 40px;
            height: 40px;
            border-radius: 20px;
        }
        .ball1 { background: red;}
        .ball2 { background: yellow;}
        .ball3 { background: green;}
    </style>
    <script type="text/javascript" src="/home/hao/node_modules/bluebird/js/browser/bluebird.js"></script>
</head>

<body>
    <div class="ball ball1" style="margin-left: 0;"></div>
    <div class="ball ball2" style="margin-left: 0;"></div>
    <div class="ball ball3" style="margin-left: 0;"></div>
    

</body>
<script type="text/javascript">
    var ball1 = document.querySelector('.ball1')
    var ball2 = document.querySelector('.ball2')
    var ball3 = document.querySelector('.ball3')
    
    function animate(ball, distance, cb){
        setTimeout(function(){
            var marginLeft = parseInt(ball.style.marginLeft, 10)
            if(marginLeft === distance){
                cb && cb()
            }
            else {
                if(marginLeft < distance){
                    marginLeft++
                } else {
                    marginLeft--
                }
                ball.style.marginLeft = marginLeft + 'px'
                animate(ball,distance,cb)
            }
        },13);
    }
    // animate(ball1, 100, function(){
    //     animate(ball2, 200, function() {
    //         animate(ball3, 300, function(){
    //             animate(ball3, 150, function(){
    //                 animate(ball2, 150, function(){
    //                     animate(ball1, 150, function(){

    //                     })
    //                 })
    //             })
    //         })
    //     })
    // })
    var Promise = window.Promise
    function promiseAnimate(ball, distance){
        return new Promise(function(resolve, reject){
            function _animate(){
                setTimeout(function(){
                    var marginLeft = parseInt(ball.style.marginLeft, 10)
                    if(marginLeft === distance){
                        resolve()
                    }
                    else {
                        if(marginLeft < distance){
                            marginLeft++
                        } else {
                            marginLeft--
                        }
                        ball.style.marginLeft = marginLeft + 'px'
                        _animate()
                    }
                },13);
            }
            _animate()
        })

    }
    promiseAnimate(ball1, 100)
        .then(function() {
            return promiseAnimate(ball2,200)
        }).then(function(){
            return promiseAnimate(ball3,300)
        }).then(function(){
            return promiseAnimate(ball3,150)
        }).then(function(){
            return promiseAnimate(ball2,150)
        }).then(function(){
            return promiseAnimate(ball1,150)
        })
</script>
</html>
  •  Promise就是對象,有三種狀態: 未完成(pending), 已完成(fulfilled), 失敗(rejected). 過程不可逆
  • Promise A與A+不一樣點
    • A+規範經過術語thenable來區分promise對象
    • A+定義onFulfilled/onRejected必須是做爲函數來調用, 並且調用過程必須是異步的
    • A+嚴格定義了then方法鏈式調用時onFulfilled/onRejected的調用順序 

  • 使用promise改進以前的爬蟲代碼:
    var http = require('http')
    var Promise = require('bluebird')
    var cheerio = require('cheerio')        //npm install cheerio
    var baseUrl = 'http://www.imooc.com/learn/'
    var url = 'http://www.imooc.com/learn/348'
    var videoIds = [728,637,197,348,259,75,134]
    
    function filterChapters(html){
        var $ = cheerio.load(html)
        var chapters = $('.chapter')
        var title = $('h2.l').text()
        var number = $($('span.meta-value.js-learn-num')).text()
    
        // courseData = {
        //     title: title,
        //     number: number,
        //     videos: [{
        //         chapterTitle: '',
        //         videos: [
        //             title: '',
        //             id: ''
        //         ]
        //     }]
        // }
        var courseData = {
            title: title,
            videos: [],
            number:number
        }
        chapters.each(function(item){
            var chapter = $(this)
            var chapterTitle = chapter.find('strong').text().trim('\n').split('\n')[0]
            var videos = chapter.find('.video').children('li')
            var chapterData = {
                chapterTitle: chapterTitle,
                videos: []
            }
            videos.each(function(item){
                var video = $(this).find(".J-media-item")
                var videoTitle = video.text().split(/\s+/).slice(1,-2).join(' ')
                var id = video.attr('href').split('video/')[1]
                chapterData.videos.push({
                    title: videoTitle,
                    id: id
                })
    
            })
            courseData.videos.push(chapterData)
        })
        return courseData
    }
    
    function printCourseInfo(coursesData){
        coursesData.forEach(function(courseData){
            // console.log(courseData.number + ' 人學過' + courseData.title + '\n')
            console.log('### ' + courseData.title + '\n')
            courseData.videos.forEach(function(item){       
                console.log(item.chapterTitle);
                item.videos.forEach(function(video){
                    console.log('   [' + video.id + ']' + video.title + '\n')
                })
                
            })
        })
        // coursesData.forEach(function(item){
            
                
        // })
    }
    function getPageAsync(url){
        return new Promise(function(resolve,reject){
            console.log('正在爬取 ' + url)
            http.get(url, function(res) {
                var html = ''
    
                res.on('data', function(data){
                    html += data
                })
    
                res.on('end', function(){
                    resolve(html)
                    // var courseData = filterChapters(html)
                    // printCourseInfo(courseData)
                })
            }).on('error', function(e){
                reject(e)
                console.log('獲取課程數據錯誤')
            })
        })
    
    }
    
    var fetchCourseArray = []
    
    videoIds.forEach(function(id){
        fetchCourseArray.push(getPageAsync(baseUrl + id))
    })
    
    Promise
     .all(fetchCourseArray)
     .then(function(pages){
        var coursesData = []
        pages.forEach(function(html){
            var courses = filterChapters(html)
            coursesData.push(courses)
        })
    
        coursesData.sort(function(a,b){
            return a.number < b.number
        })
        printCourseInfo(coursesData)
     })

  

8. Buffer API

使用Buffer來讀寫圖片的一個例子:

 1 var fs = require('fs')
 2 
 3 fs.readFile('logo.png', function(err, origin_buffer){
 4     console.log(Buffer.isBuffer(origin_buffer))
 5     fs.writeFile('logo_buffer.png', origin_buffer, function(err){
 6         if(err) console.log(err)
 7     })
 8 
 9     // var base64Image = new Buffer(origin_buffer).toString('base64')
10     var base64Image = origin_buffer.toString('base64')
11 
12     console.log(base64Image)
13 
14     var decodedImage = new Buffer(base64Image, 'base64')
15 
16     console.log(Buffer.compare(origin_buffer, decodedImage))
17 
18     fs.writeFile('logo_decodes.png', decodedImage, function(err){
19         if(err) console.log(err)
20     })
21 })

 

9. Stream API

//拷貝文件
var fs = require('fs')
var source = fs.readFileSync('../buffer/logo.png')

fs.writeFileSync('stream_copy_logo.png', source)
//拷貝圖片
var fs = require('fs')

var readStream = fs.createReadStream('stream_copy_logo.js')
var n = 0

readStream
    .on('data', function(chunk) {
        n++
        console.log('data emits')
        console.log(Buffer.isBuffer(chunk))     //true  
        // console.log(chunk.toString('utf8'))     //要讀的文件的內容

        readStream.pause()
        console.log('data pause')
        setTimeout(function(){
            console.log('data pause end')
            readStream.resume()
        }, 3000)
    })
    .on('readable', function(){
        console.log('data readable')
    })
    .on('end', function() {
        console.log(n)
        console.log('data ends')
    })
    .on('close', function() {
        console.log('data close')
    })
    .on('error', function(e){
        console.log('data read error' + e)
    })
//拷貝視頻
var fs = require('fs')

var readStream = fs.createReadStream('1.mp4')
var writeStream = fs.createWriteStream('1-stream.mp4')

readStream.on('data', function(chunk){
    //若是緩存區數據還在寫, 那麼暫停讀數據
    if( writeStream.write(chunk) === false){
        console.log('still cached')
        readStream.pause()
    }
})

readStream.on('end', function(){
    writeStream.end()
})

writeStream.on('drain', function() {
    console.log('data drains')

    readStream.resume() 
})

 

10. 流與pipe

網絡請求與pipe:

 1 var http = require('http')
 2 var fs = require('fs')
 3 var request = require('request')
 4 
 5 http
 6     .createServer(function(req, res) {
 7         //=====================常規作法
 8         // fs.readFile('./buffer/logo.png', function(err, data){
 9         //     if(err){
10         //         res.end('file not exist!')
11         //     } else {
12         //         res.writeHeader(200, {'Context-Type' : 'text/html'})
13         //         res.end(data)
14         //     }
15         // })
16 
17         //===============使用pipe方法讀取本地圖片
18         // fs.createReadStream('../buffer/logo.png').pipe(res)
19 
20         //從網絡上獲取一張圖片 在不保存的前提下再返回給瀏覽器
21         request('http://www.imooc.com/static/img/index/logo.png?t=1.1').pipe(res)
22         //pipe會自動監聽data和end事件. 可自動控制流量壓力
23     })
24     .listen(8090)

使用pipe重構上面的copy視頻的代碼:

1 var fs = require('fs')
2 fs.createReadStream('1.mp4').pipe(fs.createWriteStream('1-pipe.mp4'))

總結:

  1. 可讀流是爲了讀取外部數據, 並把數據緩存到內部的buffer數組
  2. 可寫流是爲了消費數據, 從可讀流裏獲取數據而後對獲得的chunk數據庫進行處理.
     1 var Readable = require('stream').Readable
     2 var Writable = require('stream').Writable
     3 
     4 var readStream = new Readable()
     5 var writeStream = new Writable()
     6 
     7 readStream.push('I ')
     8 readStream.push('Love ')
     9 readStream.push('Imooc\n ')
    10 readStream.push(null)
    11 
    12 writeStream._write = function(chunk, encode, cb) {
    13     console.log(chunk.toString())
    14     cb()
    15 }
    16 
    17 readStream.pipe(writeStream)

  

一個本身定製的讀寫轉換流的實現:

 1 var stream = require('stream')
 2 var util = require('util')
 3 
 4 function ReadStream(){
 5     stream.Readable.call(this)
 6 
 7 }
 8 
 9 util.inherits(ReadStream, stream.Readable)
10 
11 ReadStream.prototype._read = function(){
12     this.push('I ')
13     this.push('Love ')
14     this.push('Imooc\n ')
15     this.push(null)
16 }
17 
18 function WriteStream(){
19     stream.Writable.call(this)
20     this._cached = new Buffer('')
21 }
22 
23 util.inherits(WriteStream, stream.Writable)
24 
25 WriteStream.prototype._write = function(chunk, encode, cb){
26     console.log(chunk.toString())
27     cb()
28 }
29 
30 function TransformStream(){
31     stream.Transform.call(this)
32 }
33 
34 util.inherits(TransformStream, stream.Transform)
35 
36 TransformStream.prototype._transform = function(chunk, encode, cb){
37     this.push(chunk)
38     cb()
39 }
40 
41 TransformStream.prototype._flush = function(cb){
42     this.push('Oh Yeah!')
43     cb()
44 }
45 
46 var rs = new ReadStream()
47 var ws = new WriteStream()
48 var ts = new TransformStream()
49 
50 rs.pipe(ts).pipe(ws)
相關文章
相關標籤/搜索