一种事件循环架构
high-level
object-oriented
just-in-time
curly-bracket syntax
prototype-based object-orientation
dynamic typing
first-class functions
示例0.0:函数
var call = fn => fn(3)
var doSomething = (n) => {
console.log(n)
}
// 函数可以作为参数传给传给函数
call(doSomething)
// 使用函数很方便,可以直接匿名使用
call(() => {
console.log(2)
})Host
JavaScript Codes
Engine(v8...)
胶水语言
...
v8(c++)
otto(golang)
网络script资源
nodejs动态加载
两段不同的代码可以在不同时机被执行,且上下文可以互相侵入
示例0.1:侵入上下文
var a = 1
// eval 在当前作用域调用一段js代码
eval('a = 2')
console.log(a)示例0.2:独立上下文
const vm = require('vm');
const x = 1;
const sandbox = { x: 2 };
vm.createContext(sandbox); // Contextify the sandbox.
const code = 'x += 40; var y = 17;';
// `x` and `y` are global variables in the sandboxed environment.
// Initially, x has the value 2 because that is the value of sandbox.x.
vm.runInContext(code, sandbox);
console.log(sandbox.x); // 42
console.log(sandbox.y); // 17
console.log(x); // 1; y is not defined.asynchronous event-driven
JavaScript runtime
不是lib不是框架,与浏览器并列,一种新的宿主环境
Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.
——nodejs.org
asynchronous event-driven
示例1.0:异步事件、计时器
console.time('timeout')
// setTimeout第一个参数,是一个函数表达式
// 第二个参数时毫秒数,经过指定的延迟调用表达式
// 计时器是一种典型的宿主提供的能力
setTimeout(() => {
// 100.671ms
// console.time/timeEnd是计时api
console.timeEnd('timeout')
}, 100)
跟定时器类似,Node.js中存在多种异步事件,不同种事件的回调函数会加入不同的队列,这些队列之间存在优先级关系。事件以单线程的形式被排队调用
示例1.1:单线程
console.time('timeout')
setTimeout(() => {
// 由于线程忙,所以即时时间到了,也只能排队
// 1001.671ms
console.timeEnd('timeout')
}, 100)
// 线程阻塞
const block = ms => {
const start = Date.now()
while(Date.now() - start < ms) {}
}
block(1000)
// no data-race示例1.2:形象演示队列优先级
const fs = require('fs')
const readable = fs.createReadStream('./text')
// poll
readable.on('data', () => {
console.log('poll: ', Date.now())
})
// close
readable.on('close', () => {
console.log('close: ', Date.now())
})
// timer
setTimeout(() => {
console.log('timers: ', Date.now())
}, 1000)
// 当前线程阻塞
const block = ms => {
const start = Date.now()
while(Date.now() - start < ms) {}
}
block(3000)
// 开始处理事件队列的callback
console.log('todo queued jobs: ', Date.now())
// todo queued jobs: 1575476371564
// timers: 1575476371566
// poll: 1575476371570
// close: 1575476371571一个“nodejs”它是怎么工作的?
-> go version
go version go1.13.5 darwin/amd64
-> go get fknsrs.biz/p/ottoext
-> go get github.com/robertkrimen/otto
-> go get github.com/GeertJohan/go.rice
-> go get gopkg.in/readline.v1
-> cd ~/go/src/fknsrs.biz/p/ottoext/cmd/ottoext
-> go build main.go
-> ./main example.jsotto
ottocmd
ottoext
执行js脚本
向js注入函数
获取并执行js方法
准备js与宿主环境交互的“钩子”,如timer,网络请求...这部分在ottoext的各种包中定义
在准备了各种与宿主环境的钩子之后,它已经是一个成熟的js runtime了,在后面的js脚本中就可以使用宿主注入的方法了,这部分代码在ottocmd中
根据异步的特点,宿主环境提供的“钩子”往往是需要回调的,引擎需要获取回调函数,并且可以执行它,这部分在ottoext/loop
1)
2)
3)
回想一下刚刚提到的nodejs的核心特征
asynchronous event-driven
客服平台
周报平台
开发者平台
...
koa
mongodb
pm2
koa
示例 1.0 koa服务器 - 洋葱模型
const Koa = require('koa');
const app = new Koa();
// logger
app.use(async (ctx, next) => {
await next();
const rt = ctx.response.get('X-Response-Time');
console.log(`${ctx.method} ${ctx.url} - ${rt}`);
});
// x-response-time
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.set('X-Response-Time', `${ms}ms`);
});
// response
app.use(async ctx => {
ctx.body = 'Hello World';
});
app.listen(3000);(示例代码来自 https://koa.bootcss.com/)
ctx
next
1,贯穿整个生命周期的一个对象,包含request对象,response对象。与请求和响应的一切活动皆围绕ctx对象进行
2,它可以被任意删减修改属性,正如JavaScript的灵活性,同时也具备风险,所以中间件是危险的,引入一个中间件的同时可能会影响下游中间件
1,泛指下游所有中间件,执行可对下游所有中间件进行迭代
2,默认下游操作是一个异步的过程
简单来讲,使用async function,我们可以使用同步的代码结构,编写异步的逻辑
asyncCall1(res1 => {
asyncCall2(res2 => {
asyncCall3(res3 => {
/// ...
})
})
})asyncCall1().then(res1 => {
return asyncCall2()
}).then(res2 => {
return asyncCall3()
}).then(res3 => {
/// ...
})async function asyncCalls() {
const res1 = await asyncCall1()
const res2 = await asyncCall2()
const res3 = await asyncCall3()
// ...
}phase 1: callback
phase 2: promise
phase 3: async function
平台前端nodejs主要模块及作用
前端自动化
webpack
gulp
...
headless browser
BFF
...
打包构建
webpack,gulp
预处理,后处理
ts,scss,postcss
模版生成
...
截图服务
爬虫
搜索引擎优化
...
示例 2.0 headless browser 截图
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
console.log(await page.content());
await page.screenshot({path: 'screenshot.png'});
await browser.close();
(示例代码来自https://try-puppeteer.appspot.com )
微服务发展的产物,并不局限于nodejs
nodejs(前端)来做BFF的优势
api本是面向ui,服务端来做会有重复的理解成本和沟通成本
http request方和response方统一负责,降低理解沟通成本
服务端渲染
...