前端进阶(十三)Node.js实战

传统意义上的 JavaScript 运行在浏览器上,这是因为浏览器内核实际上分为两个部分:渲染引擎和 JavaScript 引擎。前者负责渲染 HTML + CSS,后者则负责运行 JavaScript。Chrome 使用的 JavaScript 引擎是 V8,它的速度非常快。

Node.js 是一个运行在服务端的框架,它的底层就使用了 V8 引擎。我们知道 Apache + PHP 以及 Java 的 Servlet 都可以用来开发动态网页,Node.js 的作用与他们类似,只不过是使用 JavaScript 来开发。

从定义上介绍完后,举一个简单的例子,新建一个 app.js 文件并输入以下内容:

var http = require('http');
http.createServer(function (request, response) {
    response.writeHead(200, {'Content-Type': 'text/plain'}); // HTTP Response 头部
    response.end('Hello World\n'); // 返回数据 “Hello World”
}).listen(8888); // 监听 8888 端口
// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');

 这样,一个简单的 HTTP Server 就算是写完了,输入 node app.js 即可运行,随后访问 便会看到输出结果。

为什么要用Node?

总的来说,Node.js 适合以下场景:

  1. 实时性应用,比如在线多人协作工具,网页聊天应用等。
  2. 以 I/O 为主的高并发应用,比如为客户端提供 API,读取数据库。
  3. 流式应用,比如客户端经常上传文件。
  4. 前后端分离。

实际上前两者可以归结为一种,即客户端广泛使用长连接,虽然并发数较高,但其中大部分是空闲连接。

Node.js 也有它的局限性,它并不适合 CPU 密集型的任务,比如人工智能方面的计算,视频、图片的处理等。

以下是Node的几个简单应用,供参考。

(一)爬虫

var https = require('https')

var cheerio = require('cheerio')

var baseUrl = 'https://www.imooc.com/learn/'

var url = 'https://www.imooc.com/learn/348'

var videoIds = [348, 259, 197, 134, 75]



function filterChapters(html) {

    var $ = cheerio.load(html)

    var chapters = $('.chapter')

    var title = $('hd h2').text()

    var number = parseInt($('.js-learn-num').text())

    var coursesData = {

        title: title,

        number: number,

        videos: []

    }

    chapters.each(function (item) {

        var chapter = $(this)

        var chapterTitle = chapter.find('.chapter-description').text()

        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()

            var id = video.attr('href').split('video/')[1]

            chapterData.videos.push({

                title: videoTitle,

                id: id

            })

        })

        coursesData.videos.push(chapterData)

    })

    return coursesData

}



function printCourseInfo(coursesData) {

    coursesData.forEach((courseData) => {

        console.log(courseData.number) + '人学过' + courseData.title + '\n'

    })



    coursesData.forEach(courseData => {

        console.log('###' + courseData.title + '\n')

        courseData.videos.forEach((item) => {

            var chapterTitle = item.chapterTitle

            console.log(chapterTitle + '\n')

            item.videos.forEach(video => {

                console.log('【' + video.id + '】' + video.title + '\n')

            })

        })

    });

}



function getPageAsync(url) {

    return new Promise(function (resolve, reject) {

        console.log("正在爬取" + url)

        https.get(url, function (res) {

            var html = ''

            res.on('data', function (data) {

                html += data

            })

            res.on('end', function () {

                resolve(html)

            })

        }).on('error', function () {

            console.log('获取出错')

            reject(e)

        })

    })

}

var fetchCourseArray = []

videoIds.forEach((id) => {

    fetchCourseArray.push(getPageAsync(baseUrl + id))

})



Promise.all(fetchCourseArray).then(function (pages) {

    //

    var courseData = []

    pages.forEach(function (html) {

        var courses = filterChapters(html)

        courseData.push(courses)

    })

    courseData.sort((a, b) => {

        return a.number < b.number

    })

    printCourseInfo(courseData)

})

(二)require简易实现

Node中的require是一个常见函数,为此我看了一些资料,了解原理后自己实现了一个简易的require。

 

 

 

'use strict';

function $require(id){
    let fs = require('fs');
    let path = require('path');

    let fileName = path.join(__filename, id);
    let pathName = path.basename(fileName);
    $require.cache = $require.cache || {};
    if($require.cache){
        return $require.cache[fileName].module;
    }
    const dirname = path.dirname(filename);  
    let code = fs.readFileSync(__dirname + id, 'utf8');
    
    let module = {id:fileName, exports:{}}
    let exports = module.exports;
    code = `(function($require, module, exports, __dirname, __filename){
        ${code}
    })($require, module, exports, dirname, filename)`
    eval(code)
    $require.cache[filename] = module;
    return module.exports;
} 

var m1 = $require('./module.js');//要导入的文件模块路径

(三)创建目录实现mkdirs

const fs = require('fs');
const path = require('path');

function mkdirs(pathname, callback) {
  // module.parent 拿到的是调用父对象的文件目录
  var root = path.dirname(module.parent.filename);

  pathname = path.isAbsolute(pathname) ? pathname : path.join(root, pathname)

  var relativepath = path.relative(root, pathname);

  var folders = relativepath.split(path.sep);

  try {
    var pre = '';
    folders.forEach(folder => {
      try {
        // 如果不存在则报错
        fs.statSync(path.join(root, pre, folder));
      } catch (error) {
        fs.mkdirSync(path.join(root, pre, folder));
      }

      pre = path.join(pre, folder);
    });
    callback && callback(null);
  } catch (error) {
    callback && callback(error);
  }
}

module.exports = mkdirs;


调用

var mkdirs = require('./module/mkdirs');
var path = require('path');

mkdirs('./d1/d2/d3/d4/d5', (err) => { console.log(err); });

(四)实现markdown文件监听并转化为html文件

//调用: node 本文件名 要监听的markdown文件
'use strict'

let fs = require('fs');
let path = require('path');
let marked = require('marked');//process markdown...
const browserSync = require("browser-sync");

// get target markdown file path...
const target = path.join(__dirname, process.argv[2]);

// after convert to HTML location...
var filename = target.replace(path.extname(target), '.html');

// get html file name...
var indexpath = path.basename(filename);

// Start the server
browserSync({
    notify: false,
    server: path.dirname(target),
    index: indexpath 
});

fs.watchFile(target, { interval: 200 }, (curr, prev) => {
    if(curr.mtime === prev.mtime){
        return false;
    }

    fs.readFile(target, 'utf8', (error, content) => {
        if(error){
            console.log(error)
        }
        var html = marked(content);
        template.replace(`{{{content}}}`, html);
        fs.writeFile(target.replace(path.extname(target), '.html'), html, 'utf8', (err, css) => {
            html = template.replace('{{{content}}}', html).replace('{{{styles}}}', css);

            fs.writeFile(filename, html, 'utf8', (err) => {
                browserSync.reload(indexpath);
            });
        });
    })
})

let template = `
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <style>{{{styles}}}</style>
</head>
<body>
  <div class="vs">
    {{{content}}}
  </div>
</body>
</html>
`;

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fullstack_lth

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值