Wayne-W-W / webBlog

个人博客
0 stars 0 forks source link

NodeJs从Koa框架开始(一) #7

Open Wayne-W-W opened 6 years ago

Wayne-W-W commented 6 years ago

Vscode快捷键

生成器

1.迭代器
function makeIterator (arr) {
    let nextIndex = 0;
    //返回一个迭代器
    return {
        next:() => {
            //next()方法返回的结果对象
            if(nextIndex < arr.length) {
                return { value: arr[nextIndex++], done: false}
            }else{
                return {done: true}
            }
        }
    }
}
const it = makeIterator(['吃饭','睡觉','打豆豆'])

console.log('首先',it.next().value)  //吃饭
console.log('首先',it.next().value)  //睡觉
console.log('首先',it.next().value)  //打豆豆
console.log('首先',it.next().done)   //true

return返回一个next方法

2.生成器:生成一个返回迭代器的函数,本质上操作迭代器,实际是借助生成器函数进行操作。
function *makeIterator (arr) {
    for (let i = 0; i < arr.length; i++){
        yield arr[i] 
    }
}
const gen = makeIterator(['吃饭','睡觉','打豆豆']);
console.log('首先',gen.next().value)//吃饭
console.log('首先',gen.next().value)//睡觉
console.log('首先',gen.next().value)//打豆豆
console.log('首先',gen.next().done)//true

生成器的出现简化了创建生成器这个繁琐的过程,更方便我们使用迭代器。

co

const co = require('co');
const fetch = require('node-fetch');
co(function *() {
    const res = yield fetch ('https://api.douban.com/v2/movie/1291843');
    const movie = yield res.json();
    const summary = movie.summary
    console.log(summary)
}

将传入generator function转为promise;yield只能用于对象、数组、promise(包括generator),不能yield字符串、数组。

模块加载
const fs = require('fs');
fs.writeFile

//运行时加载
//解构方式模块加载:先加载整个fs对象,在通过fs拿到writeFile——运行时加载。
const { writeFile } = require('fs');

//静态加载, 代码在编译的时候就可以拿到这个方法。
import { writeFile } from "fs";

配置bable环境

翻译小工具-fanyi模块

安装npm install fanyi -g;命令fanyi study;

gitignore

新建.gitignore文件,通用忽略文件.

#dependencies
node_modules

#logs
npm-debug.log

#Nuxt generate
dist

#System
.DS_Store

#Build
build

爬虫技术

Puppeteer

++借助node服务调用Puppeteer,Puppeteer是无头浏览器,模拟一个真实用户的网页访问,然后注入脚本,解析网页上的文本,提取目标数据.++

Puppeteer Github

安装

npm install puppeteer
#or "yarn add puppeteer"
编写爬虫脚本tralier-list.js
const url = `https://movie.douban.com/tag/#/?sort=R&range=6,=`;
const puppeteer = require("puppeteer");

const sleep = time => new Promise(resolve => {
    setTimeout(resolve, time)   
})

;(async () => {
    console.log("Start visit the target page");
    const browser = await puppeteer.launch({
        args:['--no-sandbox'],
        dumpio:false
    });
    const page = await browser.newPage();
    await page.goto(url,{
        waitUntil:'networkidle2'
    })
    await sleep(3000)
    await page.waitForSelector('.more');//加载更多按钮
    //爬去两页数据
    for(let i = 0; i < 1; i++){
        await sleep(3000);//等待3s
        await page.click('.more');//等待加载更多按钮出现
    }
    //获取爬去结果
    const result = await page.evaluate(() => {
        var $ = window.$;//jQuery
        var items = $('.list-wp a');
        var links = [];
        if(items.length >= 1){
            items.each((index,item) => {
                let it = $(item);
                let doubanId = it.find('div').data('id');
                let title = it.find('.title).text();
                let rate = Number(it.find('.rate').text())
                let poster = it.find('img').attr('src').replace('s_ratio','l_ratio');
                links.push({
                    doubanId,title,rate,poster
                })
            })
        }
        return links
    })
    browser.close();
    console.log(result)
})()
提交代码
git checkout master -b daily-6-1;//从主分支上创建一个新分支
git status -s;//查看当前分支下有哪些文件改动;M:改动文件,??还未被加到追踪历史中
git add .;//把当前改动加到缓存区
git commit -m "改动描述";
git push origin daily-6-1//在远端仓库创建一个同名分支,并同步到远端仓库
git checkout master;//切换到主分支
git merge daily-6-1;//merge本地daily-6-1
git push origin master;

Child Process子进程

Nodejs是单线程,在网站服务的主进程中跑起来若干个子进程,就算是子进程崩溃,主进程还是正常运行。
graph LR
A[进程模型]-->B[进程的9个问题]
B-->C[什么是同步异步]
B-->D[什么是异步IO]
B-->E[什么是阻塞非阻塞]
B-->F[什么是事件循环与事件驱动]
B-->G[什么是单线程]
B-->H[什么是进程]
B-->I[什么是子进程]
B-->J[怎么样来启动子进程]
B-->K[进程间如何通信]
tasks/movies.js
const cp = require('child_process');//引入子进程
const { resolve } = require('path');
;(async () => {
    //拿到爬虫脚本,通过resolve拼接相对路径
    const script = resolve(_dirname, '../crawler/trailer-list');
    //调用cp.fork方法传入两个参数,第一个爬虫脚本路径,第二个空参数,cp.fork会返回一个子进程对象. 
    const child = cp.fork(script,[])
    //声明调用辨识符,标识爬虫脚本有没有被运行过
    let invoked = false;
    //监听进程异常
    child.on('error', err => {
        if(invoked) return;
        invoked = true;
        console.log(err)
    })
    //监听进程退出
    child.on('exit', code => {
        if(invoked) return;
        invoked = true;
        let err = code === 0 ? null : new Error('exit code' + code);
        console.log(err)
    })
    //监听消息获取
    child.on('message', data => {
        let result = data.result;
        console.log(result)
    })
})
tralier-list.js进程文件添加配置
process.send({result})//发送消息
process.exit(0);//进程退出

request-promise-native服务器端对API请求
安装request
npm i request;
npm i request-promise-native;

request-promise-nativerequest库的上层封装,用了原生的promise对callback形式的request进行封装,支持await形式调用.

const rp = require('request-promise-native')
async function fetchMovie(item){
const url = `http://api.douban.com/v2/movie/subject/${item.doubanId}`;
const res = await rp(url);
return res
}
;(async () => {
let movies = [
{doubanId: 3914513},
{doubanId: 27593529}
];
let movieData = await fetchMovie(movie)
try {
movieData = JSON.parse(movieData)
} catch (err){
console.log(err)
}
})

上传图片和视频到七牛云

安装 npm i qiniu nanoid
配置七牛参数config.js
module.exports = {
//粘贴自己七牛云配置
"qiniu": {
"bucket":"",
"video":"",
"AK":"",
"SK":""
}
}
配置七牛SDK上传对象qiniu.js
const qiniu = require('qiniu');
//生成一个随机id,作为静态资源文件名
const nanoid = require('nanoid');
const config = require('../config');
//七牛的bucket 
const bucket = config.qiniu.bucket;
//生成mac
const mac = new qiniu.auth.digest.Mac(config.qiniu.AK, config.qiniu.SK);
const cfg = new qiniu.conf.Config();
const client = new.qiniu.rs.BucketManager(mac, cfg);
//上传方法 
//url素材地址,key文件名
const uploadToQiniu = async (url, key) => {
return new Promise( (resolve, reject) =>{
//client.fetch【client上fetch方法从网络获取静态资源,获取之后通过传入key对文件重命名】
//key文件名
client.fetch(url, bucket, key, (err, ret, info) =>{
if(err){
reject(err)
}else{
if(info.statusCode === 200){
resolve({ key })
}else{
reject(info)
}
}
} )
} )
}
讲图片视频素材上传至七牛云
;(async () => {
//mock数组
let movies =[{
video:'',
doubanId:'',
poster:'',
cover:''
}];
//上传素材
movies.map(async movie => {
if(movie.video && !movie.key){
try {
console.log('正在传输')
let videoData = await uploadToQiniu(movie.video, nanoid() + '.mp4');
let coverData = await uploadToQiniu(movie.cover, nanoid() + '.png');
let posterData = await uploadToQiniu(movie.poster, nanoid() + '.png');
//
if(videoData.key){
movie.videoKey = videoData.key;
}
if(coverData.key){
movie.coverKey = coverData.key;
}
if(posterData.key){
movie.posterKey = posterData.key;
}
console.log(movie)
} catch(err) {
console.log(err)
}
}
})
})

Koa与Mongodb的结合

安装Mongodb
使用mongoose数据建模库

底层数据库提供的驱动程序,也叫链接池,与数据库之间直接通信,封装之后提供了很多接口类从而达到数据增删改查

安装`npm i mongoose -s

const mongoose = require("monooge");
//本地数据库地址
const db = "mongodb://localhost/xxxx";
//指定mongoose的promise是nodejs提供的promise
mongoose.Promise = global.Promise;
exports.connect = () => {
//判断生成环境
if(process.env.NODE_ENV !== "production"){
//如果不是生产环境,打印日志
mongoose.set('debug', true)
}
mongoose.connect(db);//链接数据库
//监听断开链接,重链
mongoose.connection.on("disconnected", ()=> {
mongoose.connect(db);  
})
//错误时
mongoose.connection.on("error", err=> {
console.log(err  
})
//链接成功
mongoose.connection.once("open", err=> {
console.log('MongoDB Connected successfully')
})
}

###### 调用

const { connect } = require('../../aa.js'); ;(async () =>{ await connect() } )

Wayne-W-W commented 6 years ago

生成器:生成一个返回迭代器的函数,本质上操作迭代器,实际是借助生成器函数进行操作。