最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Node.js深入分析Koa源碼

 更新時(shí)間:2022年08月08日 09:06:34   作者:夏安  
本文主要從源碼的角度來講述 Koa,尤其是其中間件系統(tǒng)是如何實(shí)現(xiàn)的。跟 Express 相比,Koa 的源碼異常簡潔,Express 因?yàn)榘崖酚上嚓P(guān)的代碼嵌入到了主要邏輯中,因此讀 Express 的源碼可能長時(shí)間不得要領(lǐng),而直接讀 Koa 的源碼幾乎沒有什么障礙

Koa 的主要代碼位于根目錄下的 lib 文件夾中,只有 4 個(gè)文件,去掉注釋后的源碼不到 1000 行,下面列出了這 4 個(gè)文件的主要功能。

  • request.js:對 http request 對象的封裝。
  • response.js:對 http response 對象的封裝。
  • context.js:將上面兩個(gè)文件的封裝整合到 context 對象中
  • application.js:項(xiàng)目的啟動(dòng)及中間件的加載。

1. Koa 的啟動(dòng)過程

首先回憶一下一個(gè) Koa 應(yīng)用的結(jié)構(gòu)是什么樣子的。

const Koa = require('Koa');
const app = new Koa();
//加載一些中間件
app.use(...);
app.use(....);
app.use(.....);
app.listen(3000);

Koa 的啟動(dòng)過程大致分為以下三個(gè)步驟:

  • 引入 Koa 模塊,調(diào)用構(gòu)造方法新建一個(gè) app 對象。
  • 加載中間件。
  • 調(diào)用 listen 方法監(jiān)聽端口。

我們逐步來看上面三個(gè)步驟在源碼中的實(shí)現(xiàn)。

首先是類和構(gòu)造函數(shù)的定義,這部分代碼位于 application.js 中。

// application.js
const response = require('./response')
const context = require('./context')
const request = require('./request')
const Emitter = require('events')
const util = require('util')
// ...... 其他模塊
module.exports = class Application extends Emitter {
  constructor (options) {
    super()
    options = options || {}
    this.proxy = options.proxy || false
    this.subdomainOffset = options.subdomainOffset || 2
    this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For'
    this.maxIpsCount = options.maxIpsCount || 0
    this.env = options.env || process.env.NODE_ENV || 'development'
    if (options.keys) this.keys = options.keys
    this.middleware = []
    // 下面的 context,request,response 分別是從其他三個(gè)文件夾中引入的
    this.context = Object.create(context)
    this.request = Object.create(request)
    this.response = Object.create(response)
    // util.inspect.custom support for node 6+
    /* istanbul ignore else */
    if (util.inspect.custom) {
      this[util.inspect.custom] = this.inspect
    }
  }
  // ...... 其他類方法
}

首先我們注意到該類繼承于 Events 模塊,然后當(dāng)我們調(diào)用 Koa 的構(gòu)造函數(shù)時(shí),會初始化一些屬性和方法,例如以context/response/request為原型創(chuàng)建的新的對象,還有管理中間件的 middleware 數(shù)組等。

2. 中間件的加載

中間件的本質(zhì)是一個(gè)函數(shù)。在 Koa 中,該函數(shù)通常具有 ctxnext 兩個(gè)參數(shù),分別表示封裝好的 res/req 對象以及下一個(gè)要執(zhí)行的中間件,當(dāng)有多個(gè)中間件的時(shí)候,本質(zhì)上是一種嵌套調(diào)用,就像洋蔥圖一樣。

Koa 和 Express 在調(diào)用上都是通過調(diào)用 app.use() 的方式來加載一個(gè)中間件,但內(nèi)部的實(shí)現(xiàn)卻大不相同,我們先來看application.js 中相關(guān)方法的定義。

/**
 * Use the given middleware `fn`.
 *
 * Old-style middleware will be converted.
 *
 * @param {Function} fn
 * @return {Application} self
 * @api public
 */
use(fn) {
  if (typeof fn !== 'function') throw new TypeError('middleware must be a function!')
  debug('use %s', fn._name || fn.name || '-')
  this.middleware.push(fn)
  return this
}

Koa 在 application.js 中維持了一個(gè) middleware 的數(shù)組,如果有新的中間件被加載,就 push 到這個(gè)數(shù)組中,除此之外沒有任何多余的操作,相比之下,Express 的 use 方法就麻煩得多,讀者可以自行參閱其源碼。

此外,之前版本中該方法中還增加了 isGeneratorFunction 判斷,這是為了兼容 Koa1.x 的中間件而加上去的,在 Koa1.x 中,中間件都是 Generator 函數(shù),Koa2 使用的 async 函數(shù)是無法兼容之前的代碼的,因此 Koa2 提供了 convert 函數(shù)來進(jìn)行轉(zhuǎn)換,關(guān)于這個(gè)函數(shù)我們不再介紹。

if (isGeneratorFunction(fn)) {
  // ......
  fn = convert(fn)
}

接下來我們來看看對中間件的調(diào)用。

/**
 * Return a request handler callback
 * for node's native http server.
 *
 * @return {Function}
 * @api public
 */
callback () {
  const fn = compose(this.middleware)
  if (!this.listenerCount('error')) this.on('error', this.onerror)
  const handleRequest = (req, res) => {
    const ctx = this.createContext(req, res)
    return this.handleRequest(ctx, fn)
  }
  return handleRequest
}

可以看出關(guān)于中間件的核心邏輯應(yīng)該位于 compose 方法中,該方法是一個(gè)名為 Koa-compose 的第三方模塊https://github.com/Koajs/compose,我們可以看看其內(nèi)部是如何實(shí)現(xiàn)的。

該模塊只有一個(gè)方法 compose,調(diào)用方式為 compose([a, b, c, ...]),該方法接受一個(gè)中間件的數(shù)組作為參數(shù),返回的仍然是一個(gè)中間件(函數(shù)),可以將這個(gè)函數(shù)看作是之前加載的全部中間件的功能集合。

/**
 * Compose `middleware` returning
 * a fully valid middleware comprised
 * of all those which are passed.
 *
 * @param {Array} middleware
 * @return {Function}
 * @api public
 */
function compose (middleware) {
  if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
  for (const fn of middleware) {
    if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
  }
  /**
   * @param {Object} context
   * @return {Promise}
   * @api public
   */
  return function (context, next) {
    // last called middleware #
    let index = -1
    return dispatch(0)
    function dispatch (i) {
      if (i <= index) return Promise.reject(new Error('next() called multiple times'))
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next
      if (!fn) return Promise.resolve()
      try {
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)))
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}

該方法的核心是一個(gè)遞歸調(diào)用的 dispatch 函數(shù),為了更好地說明這個(gè)函數(shù)的工作原理,這里使用一個(gè)簡單的自定義中間件作為例子來配合說明。

function myMiddleware(context, next) {
  process.nextTick(function () {
    console.log('I am a middleware');
  })
  next();
}

可以看出這個(gè)中間件除了打印一條消息,然后調(diào)用 next 方法之外,沒有進(jìn)行任何操作,我們以該中間件為例,在 Koa 的 app.js 中使用 app.use 方法加載該中間件兩次。

const Koa = require('Koa');
const myMiddleware = require("./myMiddleware");
app.use(md1);
app.use(dm2);
app.listen(3000);

app 真正實(shí)例化是在調(diào)用 listen 方法之后,那么中間件的加載同樣位于 listen 方法之后。

那么 compose 方法的實(shí)際調(diào)用為 compose[myMiddleware,myMiddleware],在執(zhí)行 dispatch(0) 時(shí),該方法實(shí)際可以簡化為:

function compose(middleware) {
  return function (context, next) {
    try {
      return Promise.resolve(md1(context, function next() {
        return Promise.resolve(md2(context, function next() {
        }))
      }))
    } catch (err) {
      return Promise.reject(err)
    }
  }
}

可以看出 compose 的本質(zhì)仍是嵌套的中間件。

3. listen() 方法

這是 app 啟動(dòng)過程中的最后一步,讀者會疑惑:為什么這么一行也要算作單獨(dú)的步驟,事實(shí)上,上面的兩步都是為了 app 的啟動(dòng)做準(zhǔn)備,整個(gè) Koa 應(yīng)用的啟動(dòng)是通過 listen 方法來完成的。下面是 application.js 中 listen 方法的定義。

/**
 * Shorthand for:
 *
 *    http.createServer(app.callback()).listen(...)
 *
 * @param {Mixed} ...
 * @return {Server}
 * @api public
 */
listen(...args) {
  debug('listen')
  const server = http.createServer(this.callback())
  return server.listen(...args)
}

上面的代碼就是 listen 方法的內(nèi)容,可以看出第 3 行才真正調(diào)用了 http.createServer 方法建立了 http 服務(wù)器,參數(shù)為上節(jié) callback 方法返回的 handleRequest 方法,源碼如下所示,該方法做了兩件事:

  • 封裝 requestresponse 對象。
  • 調(diào)用中間件對 ctx 對象進(jìn)行處理。
/**
 * Handle request in callback.
 *
 * @api private
 */
handleRequest (ctx, fnMiddleware) {
  const res = ctx.res
  res.statusCode = 404
  const onerror = err => ctx.onerror(err)
  const handleResponse = () => respond(ctx)
  onFinished(res, onerror)
  return fnMiddleware(ctx).then(handleResponse).catch(onerror)
}

4. next()與return next()

我們前面也提到過,Koa 對中間件調(diào)用的實(shí)現(xiàn)本質(zhì)上是嵌套的 promise.resolve 方法,我們可以寫一個(gè)簡單的例子。

let ctx = 1;
const md1 = function (ctx, next) {
  next();
}
const md2 = function (ctx, next) {
  return ++ctx;
}
const p = Promise.resolve(
  mdl(ctx, function next() {
    return Promise.resolve(
      md2(ctx, function next() {
        //更多的中間件...
      })
    )
  })
)
p.then(function (ctx) {
  console.log(ctx);
})

代碼在第一行定義的變量 ctx,我們可以將其看作 Koa 中的 ctx 對象,經(jīng)過中間件的處理后,ctx 的值會發(fā)生相應(yīng)的變化。

我們定義了 md1md2 兩個(gè)中間件,md1 沒有做任何操作,只調(diào)用了 next 方法,md2 則是對 ctx 執(zhí)行加一的操作,那么在最后的 then 方法中,我們期望 ctx 的值為 2。

我們可以嘗試運(yùn)行上面的代碼,最后的結(jié)果卻是 undefined,在 md1next 方法前加上 return 關(guān)鍵字后,就能得到正常的結(jié)果了。

在 Koa 的源碼 application.js 中,callback 方法的最后一行:

/**
 * Return a request handler callback
 * for node's native http server.
 *
 * @return {Function}
 * @api public
 */
callback () {
  const fn = compose(this.middleware)
  if (!this.listenerCount('error')) this.on('error', this.onerror)
  const handleRequest = (req, res) => {
    const ctx = this.createContext(req, res)
    return this.handleRequest(ctx, fn)
  }
  return handleRequest
}
/**
 * Handle request in callback.
 *
 * @api private
 */
handleRequest (ctx, fnMiddleware) {
  const res = ctx.res
  res.statusCode = 404
  const onerror = err => ctx.onerror(err)
  const handleResponse = () => respond(ctx)
  onFinished(res, onerror)
  return fnMiddleware(ctx).then(handleResponse).catch(onerror)
}

中的 fnMiddleware(ctx) 相當(dāng)于之前代碼第 8 行聲明的 Promise 對象 p,被中間件方法修改后的 ctx 對象被 then 方法傳給 handleResponse 方法返回給客戶端。

每個(gè)中間件方法都會返回一個(gè) Promise 對象,里面包含的是對 ctx 的修改,通過調(diào)用 next 方法來調(diào)用下一個(gè)中間件。

fn(context, function next () {
  return dispatch(i + 1);
})

再通過 return 關(guān)鍵字將修改后的 ctx 對象作為 resolve 的參數(shù)返回。

如果多個(gè)中間件同時(shí)操作了 ctx 對象,那么就有必要使用 return 關(guān)鍵字將操作的結(jié)果返回到上一級調(diào)用的中間件里。

事實(shí)上,如果讀者去讀 Koa-router 或者 Koa-static 的源碼,也會發(fā)現(xiàn)它們都是使用 return next 方法。

5. 關(guān)于 Can’t set headers after they are sent.

這是使用 Express 或者 Koa 常見的錯(cuò)誤之一,其原因如字面意思,對于同一個(gè) HTTP 請求重復(fù)發(fā)送了 HTTP HEADER 。服務(wù)器在處理HTTP 請求時(shí)會先發(fā)送一個(gè)響應(yīng)頭(使用 writeHeadsetHeader 方法),然后發(fā)送主體內(nèi)容(通過 send 或者 end 方法),如果對一個(gè) HTTP 請求調(diào)用了兩次 writeHead 方法,就會出現(xiàn) Can't set headers after they are sent 的錯(cuò)誤提示,例如下面的例子:

const http = require("http");
http.createServer(function (req, res) {
  res.setHeader('Content-Type', 'text/html');
  res.end('ok');
  resend(req, res); // 在響應(yīng)結(jié)束后再次發(fā)送響應(yīng)信息
}).listen(5000);
function resend(req, res) {
  res.setHeader('Content-Type', 'text/html');
  res.end('error');
}

試著訪問 localhost:5000 就會得到錯(cuò)誤信息,這個(gè)例子太過直白了。下面是一個(gè) Express 中的例子,由于中間件可能包含異步操作,因此有時(shí)錯(cuò)誤的原因比較隱蔽。

const express = require('express');
const app = express();
app.use(function (req, res, next) {
  setTimeout(function () {
    res.redirect("/bar");
  }, 1000);
  next();
});
app.get("/foo", function (req, res) {
  res.end("foo");
});
app.get("/bar", function (req, res) {
  res.end("bar");
});
app.listen(3000);

運(yùn)行上面的代碼,訪問 http://localhost:3000/foo 會產(chǎn)生同樣的錯(cuò)誤,原因也很簡單,在請求返回之后,setTimeout 內(nèi)部的 redirect 會對一個(gè)已經(jīng)發(fā)送出去的 response 進(jìn)行修改,就會出現(xiàn)錯(cuò)誤,在實(shí)際項(xiàng)目中不會像 setTimeout 這么明顯,可能是一個(gè)數(shù)據(jù)庫操作或者其他的異步操作,需要特別注意。

6. Context 對象的實(shí)現(xiàn)

關(guān)于 ctx 對象是如何得到 request/response 對象中的屬性和方法的,可以閱讀 context.js 的源碼,其核心代碼如下所示。此外,delegate 模塊還廣泛運(yùn)用在了 Koa 的各種中間件中。

const delegate = require('delegates')
delegate(proto, 'response')
  .method('attachment')
  .method('redirect')
  .method('remove')
  .method('vary')
  .method('has')
  .method('set')
  .method('append')
  .method('flushHeaders')
  .access('status')
  .access('message')
  .access('body')
  .access('length')
  .access('type')
  .access('lastModified')
  .access('etag')
  .getter('headerSent')
  .getter('writable')

delegate 是一個(gè) Node 第三方模塊,作用是把一個(gè)對象中的屬性和方法委托到另一個(gè)對象上。

讀者可以訪問該模塊的項(xiàng)目地址 https://github.com/tj/node-delegates,然后就會發(fā)現(xiàn)該模塊的主要貢獻(xiàn)者還是TJ Holowaychuk。

這個(gè)模塊的代碼同樣非常簡單,源代碼只有 100 多行,我們這里詳細(xì)介紹一下。

在上面的代碼中,我們使用了如下三個(gè)方法:

  • method:用于委托方法到目標(biāo)對象上。
  • access:綜合 gettersetter,可以對目標(biāo)進(jìn)行讀寫。
  • getter:為目標(biāo)屬性生成一個(gè)訪問器,可以理解成復(fù)制了一個(gè)只讀屬性到目標(biāo)對象上。

gettersetter 這兩個(gè)方法是用來控制對象的讀寫屬性的,下面是 method 方法與 access 方法的實(shí)現(xiàn)。

/**
 * Delegate method `name`.
 *
 * @param {String} name
 * @return {Delegator} self
 * @api public
 */
Delegator.prototype.method = function(name){
  var proto = this.proto;
  var target = this.target;
  this.methods.push(name);
  proto[name] = function(){
    return this[target][name].apply(this[target], arguments);
  };
  return this;
};

method 方法中使用 apply 方法將原目標(biāo)的方法綁定到目標(biāo)對象上。

下面是 access 方法的定義,綜合了 getter 方法和 setter 方法。

/**
 * Delegator accessor `name`.
 *
 * @param {String} name
 * @return {Delegator} self
 * @api public
 */
Delegator.prototype.access = function(name){
  return this.getter(name).setter(name);
};
/**
 * Delegator getter `name`.
 *
 * @param {String} name
 * @return {Delegator} self
 * @api public
 */
Delegator.prototype.getter = function(name){
  var proto = this.proto;
  var target = this.target;
  this.getters.push(name);
  proto.__defineGetter__(name, function(){
    return this[target][name];
  });
  return this;
};
/**
 * Delegator setter `name`.
 *
 * @param {String} name
 * @return {Delegator} self
 * @api public
 */
Delegator.prototype.setter = function(name){
  var proto = this.proto;
  var target = this.target;
  this.setters.push(name);
  proto.__defineSetter__(name, function(val){
    return this[target][name] = val;
  });
  return this;
};

最后是 delegate 的構(gòu)造函數(shù),該函數(shù)接收兩個(gè)參數(shù),分別是源對象和目標(biāo)對象。

/**
 * Initialize a delegator.
 *
 * @param {Object} proto
 * @param {String} target
 * @api public
 */
function Delegator(proto, target) {
  if (!(this instanceof Delegator)) return new Delegator(proto, target);
  this.proto = proto;
  this.target = target;
  this.methods = [];
  this.getters = [];
  this.setters = [];
  this.fluents = [];
} 

可以看出 deletgate 對象在內(nèi)部維持了一些數(shù)組,分別表示委托得到的目標(biāo)對象和方法。

關(guān)于動(dòng)態(tài)加載中間件

在某些應(yīng)用場景中,開發(fā)者可能希望能夠動(dòng)態(tài)加載中間件,例如當(dāng)路由接收到某個(gè)請求后再去加載對應(yīng)的中間件,但在 Koa 中這是無法做到的。原因其實(shí)已經(jīng)包含在前面的內(nèi)容了,Koa 應(yīng)用唯一一次加載所有中間件是在調(diào)用 listen 方法的時(shí)候,即使后面再調(diào)用 app.use 方法,也不會生效了。

7. Koa 的優(yōu)缺點(diǎn)

通過上面的內(nèi)容,相信讀者已經(jīng)對 Koa 有了大概的認(rèn)識,和 Express 相比,Koa 的優(yōu)勢在于精簡,它剝離了所有的中間件,并且對中間件的執(zhí)行做了很大的優(yōu)化。

一個(gè)經(jīng)驗(yàn)豐富的 Express 開發(fā)者想要轉(zhuǎn)到 Koa 上并不需要很大的成本,唯一需要注意的就是中間件執(zhí)行的策略會有差異,這可能會帶來一段時(shí)間的不適應(yīng)。

現(xiàn)在我們來說說 Koa 的缺點(diǎn),剝離中間件雖然是個(gè)優(yōu)點(diǎn),但也讓不同中間件的組合變得麻煩起來,Express 經(jīng)過數(shù)年的沉淀,各種用途的中間件已經(jīng)很成熟;而 Koa 不同,Koa2.0 推出的時(shí)間還很短,適配的中間件也不完善,有時(shí)單獨(dú)使用各種中間件還好,但一旦組合起來,可能出現(xiàn)不能正常工作的情況。

舉個(gè)例子,如果想同時(shí)使用 routerviews 兩個(gè)中間件,就要在 render 方法前加上 return 關(guān)鍵字(和 return next()一個(gè)道理),對于剛接觸 Koa 的開發(fā)者可能要花很長時(shí)間才能定位問題所在。再例如前面的 koa-sessionKoa-router,我初次接觸這兩個(gè)中間件時(shí)也著實(shí)花了一些功夫來將他們正確地組合在一塊。雖然中間件概念的引入讓Node開發(fā)變得像搭積木一樣,但積木之間如果不能很順利地拼接在一塊的話,也會增加開發(fā)成本。

到此這篇關(guān)于Node.js深入分析Koa源碼的文章就介紹到這了,更多相關(guān)Node.js Koa內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:

相關(guān)文章

  • 基于NodeJS的前后端分離的思考與實(shí)踐(二)模版探索

    基于NodeJS的前后端分離的思考與實(shí)踐(二)模版探索

    在傳統(tǒng)的開發(fā)模式中,瀏覽器端與服務(wù)器端是由不同的前后端兩個(gè)團(tuán)隊(duì)開發(fā),但是模版卻又在這兩者中間的模糊地帶。因此模版上面總不可避免的越來越多復(fù)雜邏輯,最終難以維護(hù)。
    2014-09-09
  • node.js使用require()函數(shù)加載模塊

    node.js使用require()函數(shù)加載模塊

    本文通過幾個(gè)具體實(shí)例來分析node.js中使用require()函數(shù)來加載模塊的方法。非常的詳盡,給需要的小伙伴們參考下吧
    2014-11-11
  • 深入分析node.js的異步API和其局限性

    深入分析node.js的異步API和其局限性

    這篇文章首先給大家介紹了為什么要用異步API,其次node.js異步api在使用過程有一些什么樣的限制呢,對于這個(gè)問題我們下面來看看這篇關(guān)于node.js異步的介紹分析吧,有需要的可以參考借鑒。
    2016-09-09
  • node.js實(shí)現(xiàn)博客小爬蟲的實(shí)例代碼

    node.js實(shí)現(xiàn)博客小爬蟲的實(shí)例代碼

    這篇文章通過實(shí)例代碼來給大家介紹如何利用node.js實(shí)現(xiàn)博客小爬蟲,有需要的朋友們可以直接運(yùn)用文中給出的實(shí)例代碼來進(jìn)行實(shí)踐學(xué)習(xí),感興趣的朋友們下面來一起看看吧。
    2016-10-10
  • node.js中ws模塊創(chuàng)建服務(wù)端與客戶端實(shí)例代碼

    node.js中ws模塊創(chuàng)建服務(wù)端與客戶端實(shí)例代碼

    在Node.js中提供了http模塊與https模塊,專用于創(chuàng)建HTTP服務(wù)器、HTTP客戶端,以及HTTPS服務(wù)器及HTTPS客戶端,同時(shí)實(shí)現(xiàn)這些服務(wù)器端與客戶端之中所需進(jìn)行的處理,下面這篇文章主要給大家介紹了關(guān)于node.js中ws模塊創(chuàng)建服務(wù)端與客戶端的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • 使用基于Node.js的構(gòu)建工具Grunt來發(fā)布ASP.NET MVC項(xiàng)目

    使用基于Node.js的構(gòu)建工具Grunt來發(fā)布ASP.NET MVC項(xiàng)目

    這篇文章主要介紹了使用基于Node.js的構(gòu)建工具Grunt來發(fā)布ASP.NET MVC項(xiàng)目的教程,自動(dòng)化構(gòu)建工具Grunt具有編譯壓縮單元測試等功能,十分強(qiáng)大,需要的朋友可以參考下
    2016-02-02
  • Node.js處理HTTP請求的示例代碼

    Node.js處理HTTP請求的示例代碼

    Node.js是一個(gè)基于Chrome V8引擎的JavaScript運(yùn)行環(huán)境,它使得JavaScript可以脫離瀏覽器在服務(wù)器端運(yùn)行,Node.js的非阻塞I/O模型和事件驅(qū)動(dòng)特性使其在處理HTTP請求時(shí)表現(xiàn)出色,本文將探討Node.js如何處理HTTP請求,并提供示例代碼,需要的朋友可以參考下
    2024-09-09
  • node.js對于數(shù)據(jù)庫MySQL基本操作實(shí)例總結(jié)【增刪改查】

    node.js對于數(shù)據(jù)庫MySQL基本操作實(shí)例總結(jié)【增刪改查】

    這篇文章主要介紹了node.js對于數(shù)據(jù)庫MySQL基本操作,結(jié)合實(shí)例形式總結(jié)分析了node.js針對mysql數(shù)據(jù)庫基本配置、連接與增刪改查相關(guān)操作技巧,需要的朋友可以參考下
    2023-04-04
  • node.js中 stream使用教程

    node.js中 stream使用教程

    Stream 是一個(gè)抽象接口,Node 中有很多對象實(shí)現(xiàn)了這個(gè)接口。例如,對http 服務(wù)器發(fā)起請求的request 對象就是一個(gè) Stream,還有stdout(標(biāo)準(zhǔn)輸出)。
    2016-08-08
  • nodejs 中模擬實(shí)現(xiàn) emmiter 自定義事件

    nodejs 中模擬實(shí)現(xiàn) emmiter 自定義事件

    這篇文章主要介紹了Nodejs中自定義事件實(shí)例,比較簡單的一個(gè)例子,需要的朋友可以參考下。
    2016-02-02

最新評論

阿巴嘎旗| 白城市| 高阳县| 阿合奇县| 安岳县| 栾城县| 临沭县| 重庆市| 阿坝| 漳平市| 宣汉县| 内江市| 黄浦区| 韶关市| 上犹县| 广饶县| 梨树县| 固阳县| 东港市| 布尔津县| 平利县| 喜德县| 忻城县| 鲁甸县| 秦安县| 南涧| 工布江达县| 成武县| 洞口县| 东莞市| 同江市| 达孜县| 福鼎市| 山丹县| 鞍山市| 云龙县| 同江市| 蒲江县| 额尔古纳市| 大连市| 新余市|