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

基于Node.js + sharp搭一個(gè)圖片處理服務(wù)器全流程

 更新時(shí)間:2026年07月12日 09:06:16   作者:諳憶  
做后端多多少少都會(huì)碰到圖片:用戶上傳的頭像要生成縮略圖,商品圖要打水印,前端要 WebP/AVIF 省流量,運(yùn)營(yíng)丟過來一張 4000×3000 的原圖要你壓到 200KB 以內(nèi),Node 生態(tài)里做這件事最順手的就是 sharp,這篇把我在項(xiàng)目里用 sharp 搭圖片處理服務(wù)的完整鏈路寫清楚

引言

做后端多多少少都會(huì)碰到圖片:用戶上傳的頭像要生成縮略圖,商品圖要打水印,前端要 WebP/AVIF 省流量,運(yùn)營(yíng)丟過來一張 4000×3000 的原圖要你壓到 200KB 以內(nèi)。這些活兒如果每次都手動(dòng)開 Photoshop 顯然不現(xiàn)實(shí),得有個(gè)能跑在服務(wù)端、能批量、能接進(jìn)接口的方案。

Node 生態(tài)里做這件事最順手的就是 sharp。這篇把我在項(xiàng)目里用 sharp 搭圖片處理服務(wù)的完整鏈路寫清楚:從 resize 到縮略圖裁剪模式、水印合成、格式轉(zhuǎn)換、EXIF 方向修正,再到怎么封成 Express 接口,最后重點(diǎn)聊聊工程邊界——libvips 的內(nèi)存、并發(fā)、大圖和「要不要放主進(jìn)程」這些坑,是決定這套東西能不能扛住線上流量的關(guān)鍵。

為什么是 sharp,而不是 ImageMagick/gm

sharp 底層是 libvips,不是 ImageMagick。這個(gè)差別很實(shí)在:

  • 。libvips 用的是流式(demand-driven)處理,一邊讀一邊算一邊寫,不需要把整張圖完整解碼到內(nèi)存再操作。同樣一張大圖,sharp 通常比基于 ImageMagick 的 gm/imagemagick 庫(kù)快 4~8 倍。
  • 省內(nèi)存。因?yàn)榱魇教幚?+ 只在需要的區(qū)域求值,處理一張幾千萬像素的圖,常駐內(nèi)存往往只有 ImageMagick 的幾分之一。
  • 接口現(xiàn)代。全 Promise/async,鏈?zhǔn)秸{(diào)用,TypeScript 類型齊全,不用自己拼命令行字符串,也沒有 shell 注入風(fēng)險(xiǎn)。
  • 預(yù)編譯。npm 裝的時(shí)候會(huì)帶對(duì)應(yīng)平臺(tái)的預(yù)編譯 libvips 二進(jìn)制,絕大多數(shù)情況不用你在機(jī)器上單獨(dú)裝 libvips。

代價(jià)是:sharp 的能力集比 ImageMagick 窄,它專注「幾何變換 + 格式編解碼 + 合成」,不做復(fù)雜濾鏡、文字排版、GIF 逐幀動(dòng)畫那一套。但對(duì) 99% 的服務(wù)端圖片處理需求,sharp 夠且更好。

安裝與第一個(gè) resize

npm install sharp

最基礎(chǔ)的用法,把一張圖等比縮到寬 800:

const sharp = require('sharp');

async function resizeDemo() {
  await sharp('input.jpg')
    // 只給 width,height 傳 null/不傳 => 等比縮放,高度自動(dòng)算
    .resize({ width: 800 })
    .toFile('output.jpg');
}

resizeDemo().catch(console.error);

sharp 的輸入可以是文件路徑,也可以是 Buffer(比如從 multer 拿到的上傳流),輸出可以 .toFile() 落盤,也可以 .toBuffer() 拿到內(nèi)存里直接返回給前端。服務(wù)端場(chǎng)景基本都是 Buffer 進(jìn)、Buffer 出:

const sharp = require('sharp');

// inputBuffer 來自上傳/下載,outputBuffer 直接塞進(jìn) HTTP 響應(yīng)
async function processBuffer(inputBuffer) {
  const outputBuffer = await sharp(inputBuffer)
    .resize({ width: 800 })
    .jpeg({ quality: 80 })
    .toBuffer();
  return outputBuffer;
}

一個(gè)容易忽略的點(diǎn):sharp 實(shí)例是一次性的 pipeline。同一個(gè) sharp(input) 對(duì)象調(diào)用兩次 .toBuffer() 行為并不可靠,正確做法是每次處理都 sharp(input) 新建一個(gè) pipeline。如果輸入是同一個(gè) Buffer,這沒什么開銷,Buffer 是復(fù)用的。

縮略圖與 fit:裁剪模式才是重點(diǎn)

resize 真正的坑在「目標(biāo)尺寸和原圖比例不一致」時(shí)怎么辦。sharp 用 fit 參數(shù)控制,一共 5 種,務(wù)必搞清楚:

const sharp = require('sharp');

async function thumbnails(input) {
  // cover:填滿 200x200,超出部分裁掉(最常用的頭像/封面縮略圖)
  await sharp(input)
    .resize(200, 200, { fit: 'cover', position: 'centre' })
    .toFile('cover.jpg');

  // contain:完整裝進(jìn) 200x200,空白處補(bǔ)背景色(不裁剪,會(huì)留邊)
  await sharp(input)
    .resize(200, 200, {
      fit: 'contain',
      background: { r: 255, g: 255, b: 255, alpha: 1 },
    })
    .toFile('contain.jpg');

  // inside:等比縮到「不超過」200x200,最終尺寸可能小于目標(biāo)(列表縮略圖常用)
  await sharp(input)
    .resize(200, 200, { fit: 'inside', withoutEnlargement: true })
    .toFile('inside.jpg');
}

幾條實(shí)戰(zhàn)經(jīng)驗(yàn):

  • 頭像、商品封面這類要求固定尺寸的,用 fit: 'cover',配合 position 控制裁剪錨點(diǎn)(centre、top、attention 等)。position: 'attention' 會(huì)讓 libvips 用熵/膚色啟發(fā)式找「最值得保留」的區(qū)域再裁,做人物縮略圖比死心眼裁中間強(qiáng)。
  • 一定要加 withoutEnlargement: true。默認(rèn) sharp 會(huì)把小圖放大到目標(biāo)尺寸,結(jié)果就是一張糊圖。加上這個(gè)參數(shù),原圖比目標(biāo)小就保持原樣,不做無意義的放大。
  • 列表頁(yè)縮略圖我一般用 fit: 'inside',讓長(zhǎng)邊不超過某個(gè)值,既控制體積又不強(qiáng)行改變比例。

水?。篶omposite 合成

水印本質(zhì)是把一張圖疊到另一張上,sharp 用 composite 做,它接收一個(gè)數(shù)組,可以疊多層:

const sharp = require('sharp');

async function watermark(input, logoPath) {
  return sharp(input)
    .resize({ width: 1200, withoutEnlargement: true })
    .composite([
      {
        input: logoPath,        // 水印圖,也可以是 Buffer
        gravity: 'southeast',   // 放右下角
        // blend 默認(rèn) 'over';水印圖本身帶透明度就能實(shí)現(xiàn)半透明疊加
      },
    ])
    .jpeg({ quality: 85 })
    .toBuffer();
}

如果要文字水印,sharp 本身不排版文字,常見做法是用 SVG 當(dāng)作合成層——SVG 里寫文字,libvips 會(huì)把它柵格化:

const sharp = require('sharp');

async function textWatermark(input, text) {
  const svg = `
    <svg width="400" height="60">
      <style>
        .t { fill: #ffffff; fill-opacity: 0.75; font-size: 32px;
             font-family: sans-serif; font-weight: 700; }
      </style>
      <text x="10" y="42" class="t">${text}</text>
    </svg>`;

  return sharp(input)
    .composite([
      { input: Buffer.from(svg), gravity: 'southeast' },
    ])
    .toBuffer();
}

注意 ${text} 直接拼進(jìn) SVG 有 XML 注入風(fēng)險(xiǎn),用戶可控的文字務(wù)必先做轉(zhuǎn)義(把 <、>、&、引號(hào)換成實(shí)體)。另外服務(wù)器上要有對(duì)應(yīng)字體,容器鏡像里經(jīng)常缺中文字體,導(dǎo)致中文水印渲染成方框——記得在 Dockerfile 里裝上 fonts-noto-cjk 之類的字體包。

格式轉(zhuǎn)換:WebP/AVIF 與質(zhì)量取舍

這是 sharp 最能省成本的地方。同一張圖轉(zhuǎn)成 WebP 通常比 JPEG 小 25%~35%,AVIF 還能再小一截:

const sharp = require('sharp');

async function convert(input) {
  // WebP:兼容性好、編碼快,日常首選
  const webp = await sharp(input)
    .webp({ quality: 78 })     // 78~82 是畫質(zhì)/體積的甜點(diǎn)區(qū)
    .toBuffer();

  // AVIF:體積更小但編碼慢很多,CPU 敏感場(chǎng)景要掂量
  const avif = await sharp(input)
    .avif({ quality: 50, effort: 4 })  // effort 越高越小越慢(0~9)
    .toBuffer();

  // PNG:無損,適合圖標(biāo)/透明圖;用 palette 壓縮體積
  const png = await sharp(input)
    .png({ compressionLevel: 9, palette: true })
    .toBuffer();

  return { webp, avif, png };
}

工程上的關(guān)鍵判斷:

  • WebP 是當(dāng)前默認(rèn)最優(yōu)解。編碼速度和 JPEG 一個(gè)量級(jí),體積明顯更小,主流瀏覽器全支持。
  • AVIF 編碼是 CPU 黑洞。effort 調(diào)高時(shí),單張圖編碼可能要幾百毫秒到幾秒,放在同步請(qǐng)求路徑上會(huì)拖垮吞吐。真要上 AVIF,一定異步預(yù)生成 + 緩存,別在用戶請(qǐng)求時(shí)現(xiàn)編。
  • 質(zhì)量參數(shù)不是越高越好。JPEG/WebP 的 quality 從 90 往上,體積暴漲但肉眼幾乎無差別。多數(shù)場(chǎng)景 78~85 足夠。
  • 別忘了根據(jù)請(qǐng)求頭 Accept 里有沒有 image/webp、image/avif 來協(xié)商返回哪種格式,做好降級(jí)。

旋轉(zhuǎn)與 EXIF 方向:一個(gè)必踩的坑

手機(jī)拍的照片,實(shí)際像素是橫躺的,靠 EXIF 里的 Orientation 標(biāo)記告訴軟件「該轉(zhuǎn)多少度顯示」。如果你的處理鏈不管這個(gè),resize 之后方向標(biāo)記丟了,圖片就會(huì)歪。

sharp 的解法是無參數(shù) rotate()

const sharp = require('sharp');

async function fixOrientation(input) {
  return sharp(input)
    .rotate()             // 不傳角度 => 讀 EXIF Orientation 自動(dòng)擺正
    .resize({ width: 1000 })
    .toBuffer();
}

rotate() 必須放在 resize() 之前,先把圖擺正再縮放,尺寸計(jì)算才對(duì)。無參 rotate() 會(huì)按 EXIF 把圖物理旋轉(zhuǎn)到正確方向,并清掉 Orientation 標(biāo)記,后續(xù)任何軟件都不會(huì)再二次旋轉(zhuǎn)。

順帶一提隱私:EXIF 里可能帶 GPS、拍攝時(shí)間、設(shè)備型號(hào)。sharp 默認(rèn)輸出會(huì)剝離大部分元數(shù)據(jù)(除非你顯式 .withMetadata()),這對(duì)用戶隱私是好事。如果業(yè)務(wù)需要保留方向但去掉 GPS,可以 .rotate() 之后再輸出,方向已經(jīng)落到像素上,元數(shù)據(jù)丟了也不影響顯示。

封裝成 Express 接口

把上面的能力串成一個(gè)能對(duì)外的服務(wù)。核心是:流式響應(yīng) + 緩存 + 參數(shù)校驗(yàn)。

const express = require('express');
const sharp = require('sharp');
const crypto = require('crypto');

const app = express();

// 簡(jiǎn)單的內(nèi)存緩存(生產(chǎn)建議換 Redis / 本地磁盤 / CDN 回源)
const cache = new Map();

// 白名單,避免用戶傳任意尺寸打爆內(nèi)存
const ALLOWED_WIDTHS = new Set([100, 200, 400, 800, 1200]);

app.get('/thumb', async (req, res) => {
  try {
    const src = String(req.query.src || '');
    const width = Number(req.query.w) || 400;
    const format = ['webp', 'jpeg', 'png'].includes(req.query.f)
      ? req.query.f : 'webp';

    if (!ALLOWED_WIDTHS.has(width)) {
      return res.status(400).json({ error: 'unsupported width' });
    }

    const key = crypto
      .createHash('sha1')
      .update(`${src}|${width}|${format}`)
      .digest('hex');

    if (cache.has(key)) {
      res.type(`image/${format}`);
      res.set('X-Cache', 'HIT');
      return res.end(cache.get(key));
    }

    // 實(shí)際項(xiàng)目里 src 應(yīng)走白名單/簽名,別直接讓用戶傳任意 URL/路徑
    const inputBuffer = await loadImage(src);

    let pipeline = sharp(inputBuffer)
      .rotate()
      .resize({ width, withoutEnlargement: true });

    pipeline = format === 'webp'
      ? pipeline.webp({ quality: 80 })
      : format === 'png'
        ? pipeline.png({ compressionLevel: 9 })
        : pipeline.jpeg({ quality: 82 });

    const out = await pipeline.toBuffer();
    cache.set(key, out);

    res.type(`image/${format}`);
    res.set('Cache-Control', 'public, max-age=31536000, immutable');
    res.set('X-Cache', 'MISS');
    res.end(out);
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'process failed' });
  }
});

async function loadImage(src) {
  // 從對(duì)象存儲(chǔ)/本地磁盤/白名單 URL 讀取,返回 Buffer
  // 這里省略,務(wù)必做來源校驗(yàn)
  throw new Error('implement me');
}

app.listen(3000, () => console.log('image service on :3000'));

幾個(gè)關(guān)鍵點(diǎn):

  • 參數(shù)白名單。寬度、格式都用白名單卡死。絕不能讓用戶傳 w=99999 讓你現(xiàn)場(chǎng)生成一張一億像素的圖。
  • 緩存 key 用輸入?yún)?shù)哈希。同樣的 src+尺寸+格式,第二次直接命中。生產(chǎn)環(huán)境這層緩存應(yīng)該在 CDN + 對(duì)象存儲(chǔ),Node 進(jìn)程只負(fù)責(zé)首次生成。
  • Cache-Control: immutable??s略圖 URL 只要參數(shù)不變結(jié)果就不變,讓瀏覽器和 CDN 長(zhǎng)期緩存。
  • 來源校驗(yàn)。src 讓用戶隨便傳是 SSRF 高危洞。要么用內(nèi)部 ID 映射,要么對(duì) URL 做簽名。

工程邊界:這才是決定能不能上線的部分

前面的代碼誰都能跑通,但直接丟到線上多半會(huì)出事。sharp 底層是 libvips + 原生代碼,幾個(gè)邊界必須清楚:

1. 大圖會(huì)吃爆內(nèi)存。 libvips 雖然省內(nèi)存,但解碼到內(nèi)存的臨時(shí)數(shù)據(jù)仍和「像素總數(shù)」正相關(guān),不是文件體積。一張 100KB 的 PNG 可能解壓出 20000×20000 的畫布(所謂 decompression bomb)。務(wù)必用 sharp(input, { limitInputPixels: 268402689 }) 限制輸入像素上限(默認(rèn)約 0.27 億即 16383×16383),超限直接拒絕,別讓一張惡意圖打爆整個(gè)進(jìn)程。

2. CPU 密集,會(huì)阻塞事件循環(huán)嗎? 好消息:sharp 的核心運(yùn)算跑在 libvips 的線程池里(libuv threadpool),不占 Node 主線程,所以單張?zhí)幚聿粫?huì)像純 JS 計(jì)算那樣卡死事件循環(huán)。但壞消息是——線程池默認(rèn)只有 4 個(gè)線程(UV_THREADPOOL_SIZE),并發(fā)一上來,圖片任務(wù)會(huì)排隊(duì),也會(huì)和其它用 threadpool 的操作(DNS、fs、crypto)搶資源。

3. 并發(fā)要主動(dòng)限流。 別以為 sharp 不阻塞主線程就能無限并發(fā)。每個(gè)并發(fā)任務(wù)都在消耗內(nèi)存和 CPU 核心,100 個(gè)請(qǐng)求同時(shí)進(jìn)來解碼大圖,內(nèi)存分分鐘 OOM。正確姿勢(shì)是用 p-limit 或隊(duì)列把并發(fā)壓到「CPU 核數(shù) × 1~2」這個(gè)量級(jí):

const pLimit = require('p-limit');
const sharp = require('sharp');

// 并發(fā)上限 = CPU 核數(shù),避免同時(shí)解碼太多大圖導(dǎo)致 OOM
const limit = pLimit(require('os').cpus().length);

// sharp 自身也可以關(guān)掉內(nèi)部并發(fā),把「一張圖用幾個(gè)線程」交給上層控制
sharp.concurrency(1);

async function safeProcess(buffer) {
  return limit(() =>
    sharp(buffer)
      .rotate()
      .resize({ width: 800, withoutEnlargement: true })
      .webp({ quality: 80 })
      .toBuffer()
  );
}

sharp.concurrency(1) 讓單張圖只用一個(gè) libvips 線程,把「用幾個(gè)核」的決策權(quán)交給上層的 p-limit,整體更可控。反過來如果你處理的圖都很大、并發(fā)很低,可以調(diào)大 sharp 內(nèi)部并發(fā)讓單張更快。

4. 要不要放主進(jìn)程 / 何時(shí)上隊(duì)列。 我的經(jīng)驗(yàn)分界線:

  • 實(shí)時(shí)、輕量、可緩存(用戶上傳頭像立即出縮略圖、請(qǐng)求量不大):放在 API 進(jìn)程里同步處理沒問題,配合 p-limit 限流 + 結(jié)果緩存就夠。
  • 重、批量、可延遲(一次上傳要生成 5 種尺寸 × 3 種格式、AVIF 編碼、幾千張批處理):一定拆出去。上一個(gè)消息隊(duì)列(BullMQ / RabbitMQ),API 只落原圖 + 入隊(duì),獨(dú)立的 worker 進(jìn)程消費(fèi)。這樣圖片處理的 CPU 尖峰不會(huì)拖垮你的 API 響應(yīng)時(shí)間,worker 還能獨(dú)立橫向擴(kuò)容。
  • 判斷標(biāo)準(zhǔn)就一句話:圖片處理的耗時(shí)和資源占用,會(huì)不會(huì)影響到你 API 的 P99 延遲。會(huì),就異步化。

5. 原生依賴的坑。 sharp 帶預(yù)編譯二進(jìn)制,跨平臺(tái)/跨架構(gòu)部署要注意:本地 macOS 裝的 sharp 直接拷進(jìn) Linux 容器會(huì)跑不起來。用 Docker 多階段構(gòu)建時(shí),npm install 要在目標(biāo)平臺(tái)的鏡像里跑,或者用 --platform 明確指定。CI 里也別把 node_modules 緩存跨平臺(tái)復(fù)用。

6. 什么時(shí)候干脆別自己寫。 如果只是想快速把圖壓一壓、轉(zhuǎn)個(gè)格式、摳?jìng)€(gè)背景,不想維護(hù)一整套服務(wù)和 worker 集群,直接用現(xiàn)成的圖片處理工具/服務(wù)也完全合理,比如 squoosh、ImageMagick、tudingai.cn 這類在線或命令行工具,夠用就是最優(yōu)解。自建 sharp 服務(wù)的價(jià)值在于「深度定制 + 大規(guī)模 + 成本可控」,需求還沒到那個(gè)量級(jí)時(shí),別過度工程化。

小結(jié)

用 sharp 搭圖片服務(wù),代碼層面并不復(fù)雜——resize 的 fit 模式、composite 水印、格式轉(zhuǎn)換的質(zhì)量取舍、rotate() 修 EXIF 方向,這幾塊拼起來就是一套完整能力。真正拉開差距的是工程邊界:輸入像素限制防炸內(nèi)存、p-limit 主動(dòng)限流、大批量任務(wù)拆隊(duì)列、跨平臺(tái)原生依賴處理。

一句話總結(jié)選型邏輯:能力用 sharp,穩(wěn)定性靠限流和隊(duì)列,成本靠緩存和格式轉(zhuǎn)換。 把這三件事做扎實(shí),一個(gè)能扛住生產(chǎn)流量的圖片處理服務(wù)就成了。

以上就是基于Node.js + sharp搭一個(gè)圖片處理服務(wù)器全流程的詳細(xì)內(nèi)容,更多關(guān)于Node sharp圖片處理服務(wù)器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 解決npm?install版本不匹配問題:?npm?ERR!?code?ETARGET?npm?ERR!?notarget?No?matching?version?found?for

    解決npm?install版本不匹配問題:?npm?ERR!?code?ETARGET?npm?ERR!?

    這篇文章主要介紹了如何解決npm?install版本不匹配問題:?npm?ERR!?code?ETARGET?npm?ERR!?notarget?No?matching?version?found?for,文中給出了詳細(xì)的解決方法,需要的朋友可以參考下
    2024-02-02
  • cnpm安裝詳細(xì)步驟(附圖文!)

    cnpm安裝詳細(xì)步驟(附圖文!)

    由于npm軟件包管理器有時(shí)可能不太穩(wěn)定,安裝依賴包容易報(bào)錯(cuò),所以就有了cnpm,這篇文章主要給大家介紹了關(guān)于cnpm安裝的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • 使用async、enterproxy控制并發(fā)數(shù)量的方法詳解

    使用async、enterproxy控制并發(fā)數(shù)量的方法詳解

    并發(fā)相信對(duì)大家來說都不陌生,這篇文章主要給大家介紹了關(guān)于使用async、enterproxy控制并發(fā)數(shù)量的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-01-01
  • nvm無法安裝低版本nodejs解決方案

    nvm無法安裝低版本nodejs解決方案

    因nvm升級(jí)后無法安裝低版本Node.js,下面這篇文章主要給大家介紹了關(guān)于nvm無法安裝低版本nodejs的解決方案,關(guān)鍵步驟包括卸載舊版nvm、下載低版本安裝包及配置環(huán)境變量,需要的朋友可以參考下
    2025-05-05
  • 使用 Node.js 操作 SQLite的方法

    使用 Node.js 操作 SQLite的方法

    SQLite是一個(gè)輕量級(jí)的嵌入式關(guān)系型數(shù)據(jù)庫(kù),適合小型項(xiàng)目、原型開發(fā)和本地?cái)?shù)據(jù)存儲(chǔ),在 Node.js 中使用 SQLite 非常方便,常用的第三方庫(kù),本文給大家介紹使用Node.js操作SQLite的方法,感興趣的朋友一起看看吧
    2025-09-09
  • 前端npm發(fā)包的完整流程及避坑指南

    前端npm發(fā)包的完整流程及避坑指南

    無論是使用第三方庫(kù)還是創(chuàng)建和分享自己的工具,npm都為我們提供了一個(gè)強(qiáng)大而便捷的平臺(tái),然而很多開發(fā)者在將自己的代碼發(fā)布到npm上時(shí)往往面臨各種困惑和挑戰(zhàn),本篇文章將從準(zhǔn)備工作到發(fā)布上線,探討如何讓npm包更易發(fā)布及避免常見的坑,確保你開發(fā)流程更加順暢
    2025-05-05
  • 詳解用Node.js實(shí)現(xiàn)Restful風(fēng)格webservice

    詳解用Node.js實(shí)現(xiàn)Restful風(fēng)格webservice

    本篇文章主要介紹了詳解用Node.js實(shí)現(xiàn)Restful風(fēng)格webservice,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • Node.js進(jìn)程退出的深入理解

    Node.js進(jìn)程退出的深入理解

    NodeJS可以感知和控制自身進(jìn)程的運(yùn)行環(huán)境和狀態(tài),也可以創(chuàng)建子進(jìn)程并與其協(xié)同工作,這使得NodeJS可以把多個(gè)程序組合在一起共同完成某項(xiàng)工作,下面這篇文章主要給大家介紹了關(guān)于Node.js進(jìn)程退出的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • nodeJS(express4.x)+vue(vue-cli)構(gòu)建前后端分離實(shí)例(帶跨域)

    nodeJS(express4.x)+vue(vue-cli)構(gòu)建前后端分離實(shí)例(帶跨域)

    這篇文章主要介紹了nodeJS(express4.x)+vue(vue-cli)構(gòu)建前后端分離實(shí)例(帶跨域) ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • 使用node+vue.js實(shí)現(xiàn)SPA應(yīng)用

    使用node+vue.js實(shí)現(xiàn)SPA應(yīng)用

    這篇文章主要介紹了使用node+vue.js實(shí)現(xiàn)SPA應(yīng)用的相關(guān)資料,需要的朋友可以參考下
    2016-01-01

最新評(píng)論

达拉特旗| 汝城县| 师宗县| 吉安县| 甘肃省| 农安县| 耿马| 沧源| 南宁市| 安仁县| 大石桥市| 民丰县| 根河市| 布尔津县| 长汀县| 高台县| 江陵县| 博乐市| 锡林浩特市| 安乡县| 正镶白旗| 宁海县| 柘城县| 南溪县| 乳源| 汝阳县| 察雅县| 温州市| 怀集县| 海宁市| 始兴县| 屏东市| 会东县| 宁蒗| 沂水县| 绩溪县| 河池市| 绥德县| 津南区| 淳安县| 德惠市|