전단 면접 - 단판 koa 실현
koa 의 사용 은 매우 간단 합 니 다. 의존 도 를 도입 하여 작성 합 니 다.
const Koa = require('koa')
let app = new Koa()
app.use((ctx, next) => {
console.log(ctx)
})
app.listen(4000)
그리고 브 라 우 저 에서 열기
http://127.0.0.1:4000
하면 접근 할 수 있 습 니 다.반환 이 지정 되 지 않 았 다 면
body
koa 는 기본적으로 처리 되 었 습 니 다 Not Found
ctx 코드 를 더 확장 해서 ctx 위 에 어떤 것 이 있 는 지 보 세 요.
// ...
console.log(ctx)
console.log('native req ----') // node req
console.log(ctx.req.url)
console.log(ctx.request.req.url)
console.log('koa request ----') // koa request
console.log(ctx.url)
console.log(ctx.request.url)
// native req ----
// /
// /
// koa request ----
// /
// /
// ...
이상 코드 는 창고 에 보관 하고 스스로 찾 습 니 다.
koa 홈 페이지 에 서 는 ctx 에 일련의
request
과 response
속성 별명 을 마 운 트 했다 는 설명 이 있 습 니 다.ctx = {}
ctx.request = {}
ctx.response = {}
ctx.req = ctx.request.req = req
ctx.res = ctx.response.res = res
// ctx.url ctx.request.url
next
아래 코드 는 창고 에 보관 하고 스스로 찾 습 니 다.
next 를 사용 해 보 세 요.
const Koa = require('koa')
let app = new Koa()
app.use((ctx, next) => {
console.log(1)
next()
console.log(2)
})
app.use((ctx, next) => {
console.log(3)
next()
console.log(4)
})
app.use((ctx, next) => {
console.log(5)
next()
console.log(6)
})
app.listen(4000)
// 1
// 3
// 5
// 6
// 4
// 2
위의 코드 인쇄 결 과 를 통 해 알 수 있 듯 이 next 의 역할 은 바로 자리 표시 자 를 만 드 는 것 이다.다음 과 같은 형식 으로 볼 수 있다.
app.use((ctx, next) => {
console.log(1)
app.use((ctx, next) => {
console.log(3)
app.use((ctx, next) => {
console.log(5)
next()
console.log(6)
})
console.log(4)
})
console.log(2)
})
이것 이 바로 양파 모형 이다.
만약 어떤 중간 부품 에 비동기 코드 가 있다 면?
const Koa = require('koa')
let app = new Koa()
//
const logger = () => {
return new Promise((resolve, reject) => {
setTimeout(_ => {
console.log('logger')
resolve()
}, 1000)
})
}
app.use((ctx, next) => {
console.log(1)
next()
console.log(2)
})
app.use(async (ctx, next) => {
console.log(3)
await logger()
next()
console.log(4)
})
app.use((ctx, next) => {
console.log(5)
next()
console.log(6)
})
app.listen(4000)
// 1
// 3
// 2
// 1s
// logger
// 5
// 6
// 4
이때 인쇄 결 과 는 우리 가 예상 한 결과 가 아니 라 우리 가 기대 하 는 것 은
1 -> 3 -> 1s logger -> 5-> 6-> 4 ->2
이다.이때 우 리 는
next
앞 에 하 나 를 더 해 야 한다 await
.// ...
app.use(async (ctx, next) => {
console.log(1)
await next()
console.log(2)
})
// ...
koa 소스 코드 간단하게 읽 기
koa
더 작고 표 현 력 이 있 으 며 건장 한 web
개발 구조 가 되도록 노력 합 니 다.그 소스 코드 도 매우 가 볍 고 읽 기 쉽다.
핵심 파일 네 개
application.js
: 간단 한 포장 http.createServer()
및 통합 context.js
context.js
: 대리 및 통합 request.js
과 response.js
request.js
: 원생 req
을 바탕 으로 포장 하 는 것 이 더 좋다 response.js
: 원생 res
을 바탕 으로 포장 하 는 것 이 더 좋다 아래 와 관련 된 코드 는 창고 에 저장 되 어 있 으 며, 필요 한 것 은 스스로 찾 습 니 다.
koa 는 ES6 로 이 루어 졌 는데 주로 두 가지 핵심 방법
app.listen()
과 app.use((ctx, next) =< { ... })
이다.먼저
application.js
에서 실현 app.listen()
const http = require('http')
class Koa {
constructor () {
// ...
}
//
handleRequest (req, res) {
// ...
}
listen (...args) {
let server = http.createServer(this.handleRequest.bind(this))
server.listen(...args)
}
}
module.exports = Koa
뭐 공부 해요?
위의 간단 한 사용 ctx 에서 볼 수 있 습 니 다.
ctx = {}
ctx.request = {}
ctx.response = {}
ctx.req = ctx.request.req = req
ctx.res = ctx.response.res = res
ctx.xxx = ctx.request.xxx
ctx.yyy = ctx.response.yyy
우 리 는 상기 몇 개의 대상 이 필요 하 며, 최종 적 으로 모두
ctx
대상 에 대리 되 어야 한다.세 파일 만 들 기
context.js/request.js/response.js
request.js
내용const url = require('url')
let request = {}
module.exports = request
response.js
내용let response = {}
module.exports = response
context.js
내용let context = {}
module.exports = context
application.js
에 위의 세 개의 파일 을 도입 하여 인 스 턴 스 에 올 립 니 다.const context = require('./context')
const request = require('./request')
const response = require('./response')
class Koa extends Emitter{
constructor () {
super()
// Object.create
this.context = Object.create(context)
this.request = Object.create(request)
this.response = Object.create(response)
}
}
등 호 를 직접 사용 하여 값 을 부여 할 수 없 기 때문에 변수 속성 을 수정 할 때 원본 변 수 를 직접 변경 합 니 다. 대상 이 같은 메모리 공간 을 참조 하기 때 문 입 니 다.
그래서
Object.create
방법 으로 의존 을 차단 하 는 것 은function create (parentPrototype) {
function F () {}
F.prototype = parentPrototype
return new F()
}
그리고 사용자 요청 을 처리 하고
ctx
에서 대리 request / response
//
createContext (req, res) {
let ctx = this.context
//
ctx.request = this.request
ctx.req = ctx.request.req = req
//
ctx.response = this.response
ctx.res = ctx.response.res = res
return ctx
}
handleRequest (req, res) {
let ctx = this.createContext(req, res)
return ctx
}
context.js
에서 __defineGetter__ / __defineSetter__
를 사용 하여 대 리 를 실현 하 는데 그 는 Object.defineProperty()
방법의 변종 으로 따로 설정 get/set
할 수 있 고 덮어 쓰 지 않 습 니 다.let context = {}
//
function defineGetter (key, property) {
context.__defineGetter__ (property, function () {
return this[key][property]
})
}
//
function defineSetter (key, property) {
context.__defineSetter__ (property, function (val) {
this[key][property] = val
})
}
// request
defineGetter('request', 'path')
defineGetter('request', 'url')
defineGetter('request', 'query')
// response
defineGetter('response', 'body')
defineSetter('response', 'body')
module.exports = context
request.js
에서 ES5 가 제공 하 는 속성 접근 기 를 사용 하여 패 키 징 을 실현 합 니 다.const url = require('url')
let request = {
get url () {
return this.req.url // this ctx.request
},
get path () {
let { pathname } = url.parse(this.req.url)
return pathname
},
get query () {
let { query } = url.parse(this.req.url, true)
return query
}
// ...
}
module.exports = request
response.js
에서 ES5 가 제공 하 는 속성 접근 기 를 사용 하여 패 키 징 을 실현 합 니 다.let response = {
set body (val) {
this._body = val
},
get body () {
return this._body // this ctx.response
}
// ...
}
module.exports = response
이상 은 패키지
request/response
를 실현 하고 ctx
에 대리 되 었 습 니 다.ctx = {}
ctx.request = {}
ctx.response = {}
ctx.req = ctx.request.req = req
ctx.res = ctx.response.res = res
ctx.xxx = ctx.request.xxx
ctx.yyy = ctx.response.yyy
next 구 축 된 양파 모형
다음은 koa 의 두 번 째 방법
app.use((ctx, next) =< { ... })
을 실현 합 니 다.use 에는
cookie、session、static...
등 처리 함수 가 하나씩 저장 되 어 있 으 며
형식 으로 실 행 됩 니 다. constructor () {
// ...
//
this.middlewares = []
}
//
use (fn) {
this.middlewares.push(fn)
}
사용자 요청 을 처리 할 때 등 록 된 미들웨어 를 실행 하 기 를 기대 합 니 다.
//
compose (middlewares, ctx) {
function dispatch (index) {
//
// promise
if (index === middlewares.length) return Promise.resolve()
let middleware = middlewares[index]
// , , await
// promise
return Promise.resolve(middleware(ctx, () => dispatch(index + 1)))
}
return dispatch(0)
}
//
handleRequest (req, res) {
let ctx = this.createContext(req, res)
this.compose(this.middlewares, ctx)
return ctx
}
이상 의
dispatch
교체 함 수 는 여러 곳 에서 활용 되 는데 예 를 들 어
도 koa
의 핵심 이다.미들웨어 에 비동기 코드 가 포함 되 어 있 는데 어떻게 정확 한 집행 을 보장 합 니까?
되 돌아 오 는 promise 는 주로 미들웨어 에 비동기 코드 가 들 어 있 는 상황 을 처리 하기 위해 서 입 니 다.
모든 미들웨어 가 실 행 된 후 페이지 를 렌 더 링 해 야 합 니 다.
//
handleRequest (req, res) {
let ctx = this.createContext(req, res)
res.statusCode = 404 // 404 body
let ret = this.compose(this.middlewares, ctx)
ret.then(_ => {
if (!ctx.body) { // body
res.end(`Not Found`)
} else if (ctx.body instanceof Stream) { //
res.setHeader('Content-Type', 'text/html;charset=utf-8')
ctx.body.pipe(res)
} else if (typeof ctx.body === 'object') { //
res.setHeader('Content-Type', 'text/josn;charset=utf-8')
res.end(JSON.stringify(ctx.body))
} else { //
res.setHeader('Content-Type', 'text/html;charset=utf-8')
res.end(ctx.body)
}
})
return ctx
}
여러 가지 상황 을 고려 하여 겸용 해 야 한다.
next 를 여러 번 호출 하여 혼란 을 야기 하 는 문 제 를 해결 하 다.
이상 코드 를 통 해 다음 과 같은 테스트 를 진행 합 니 다.
실행 결 과 는?
// 1 => 3 =>1s,logger => 4
// => 3 =>1s,logger => 4 => 2
우리 의 기대 에 결코 만족 하지 않 는 다.
실행 과정 은 다음 과 같 기 때문이다.
두 번 째 단계 에서 들 어 오 는 i 값 은 1 입 니 다. 첫 번 째 미들웨어 함수 내부 이기 때 문 입 니 다. 그러나 copose 내부 의 index 는 이미 2 이기 때문에 i < 2, 그래서 잘못 보 고 했 습 니 다. 한 미들웨어 함수 내부 에서 next 함 수 를 여러 번 호출 할 수 없 음 을 알 수 있 습 니 다.
해결 방법 은 fllag 를 양파 모델 로 실행 중인 함수 미들웨어 의 아래 표 시 를 기록 하 는 것 입 니 다. 한 미들웨어 에서 next 를 두 번 실행 하면 index 는 fllag 보다 작 습 니 다.
/**
*
* @param {Array} middlewares
* @param {context} ctx
*/
compose (middlewares, ctx) {
let flag = -1
function dispatch (index) {
// 3)flag
// 3.1) next index flag
// if (index <= flag) return Promise.reject(new Error('next() called multiple times'))
flag = index
// 2) :
// 2.1) promise
if (index === middlewares.length) return Promise.resolve()
// 1) , , await
// 1.1) promise
let middleware = middlewares[index]
return Promise.resolve(middleware(ctx, () => dispatch(index + 1)))
}
return dispatch(0)
}
이벤트 기반 드라이브 처리 이상
중간 부품 에 나타 난 이상 을 어떻게 처리 합 니까?
Node
사건 으로 구동 되 기 때문에 우 리 는 events
모듈 만 계승 하면 된다.const Emitter = require('events')
class Koa extends Emitter{
// ...
//
handleRequest (req, res) {
// ...
let ret = this.compose(this.middlewares, ctx)
ret.then(_ => {
// ...
}).catch(err => { //
this.emit('error', err)
})
return ctx
}
}
그리고 위 에서 이상 포획 을 할 때 아래 와 같이 사용 하면 됩 니 다.
const Koa = require('./src/index')
let app = new Koa()
app.on('error', err => {
console.log(err)
})
테스트 사례 코드 는 창고 에 저장 되 어 있 으 며 필요 한 자체 추출 입 니 다.
총결산
이상 을 통 해 우 리 는 간단 하고 쉬 운
KOA
파일 을 실 현 했 고 request/response.js
파일 은 더 많은 속성 을 지원 해 야 합 니 다.전체 코드 와 테스트 용례 는 @ careteen / koa 에 저장 되 어 있 으 며, 관심 이 있 으 면 디 버 깅 하 러 갈 수 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
koa2 데이터api 중간부품 디자인 모델의 실현 방법모든 데이터베이스 읽기를 가정하면 httpapi 인터페이스 요청은 하나의 중간부품으로 중간부품을 플러그인으로 삼아 데이터를 얻을 위치를 삽입합니다. api.js db.js 직렬 연결 app.js 보기에는 매우 조화롭...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.