Node.js和瀏覽器之間的差異

Node.js和瀏覽器都使用JavaScript作為它們的編程語言。 在瀏覽器中構建應用程序與構建Node.js應用程序完全不同。 儘管它們都是使用JavaScript,但是它們存在一些關鍵的差異,這使得兩者的開發體驗截然不同。 作為一名前端開發人員,經常使用JavaScript的優勢之一是可以使用同一種語言來編程前端和後端。 這是一個巨大的機會,因為我們知道全面學習一門編程語言有多困難,通過使用同一種語言在網絡上執行所有工作(包括客戶端和服務器端),你處於一個獨特的優勢位置。 不同的是生態系統。 在瀏覽器中,大部分時間你在處理的是與DOM或其他Web平台API的交互,例如Cookie。在Node中,當然沒有這些東西。你沒有瀏覽器提供的document、window和其他對象。 另一個重大的不同是在Node.js中你可以控制環境。除非你正在構建可以在任何地方部署的開源應用程序,否則你知道將在哪個Node版本上運行應用程序。與瀏覽器環境相比,你無法選擇訪問者使用的瀏覽器,這非常方便。 這意味著你可以使用所有由你使用的Node版本支持的現代ES6-7-8-9 JavaScript。 由於JavaScript發展迅速,但瀏覽器可能有點慢,用戶更新也可能有點慢,有時在Web上,你只能使用舊版的JavaScript / ECMAScript。 在將代碼發送到瀏覽器之前,您可以使用Babel將代碼轉換為ES5兼容的代碼,但在Node中,您不需要這樣做。 另一個差異是Node使用了CommonJS模塊系統,而在瀏覽器中,我們開始看到正在實現的ES模塊標準。 實際上,這意味著在目前我們在Node中使用require(),而在瀏覽器中使用import。

Node.js的簡史

回顧Node.js從2009年到現在的歷史 你可能難以置信,但Node.js只有9歲。 相比之下,JavaScript已經有23歲了,而我們所熟悉的網路(在Mosaic問世之後)已經有25歲了。 對於一個技術而言,9年的歷史只是極短暫的時間,但Node.js似乎已經存在了很久很久。 我很榮幸從它剛出生的那天開始就與Node一起工作,儘管當時只有很少的資訊,但你已經能夠感覺到它是一個重大的事物。 在這篇文章中,我想從歷史的角度來概述Node的大局。 一點歷史 2009年 2010年 2011年 2012年 2013年 2014年 2015年 2016年 2017年 2018年 2019年 2020年 一點歷史 JavaScript是一種由Netscape創建的的網頁瀏覽器操控語言,用於操控瀏覽器內部的網頁,Netscape Navigator。 Netscape的業務模式之一是出售Web伺服器,其中包括一個名為Netscape LiveWire的環境,可以使用伺服器端的JavaScript創建動態網頁。因此,伺服器端JavaScript的概念並不是由Node.js引入的,但它的歷史和JavaScript一樣久遠,只是當時並不成功。 導致Node.js崛起的重要因素之一就是時機。幾年來,JavaScript被視為一種認真的語言,多虧了“Web 2.0”應用程序,這些應用程序向世界展示了現代化Web體驗的可能性(比如Google Maps或GMail)。 JavaScript引擎的性能水平大幅提高,多虧於瀏覽器競爭的戰鬥,這場戰鬥至今依然激烈進行中。每個主要瀏覽器背後的開發團隊每天都在努力提供更好的性能,這對於JavaScript作為一個平台來說是個巨大的勝利。Node.js在幕後使用的V8引擎就是其中之一,特別是Chrome的JS引擎。 但當然,Node.js不僅僅因為純粹的運氣或時機而受歡迎。它在JavaScript在服務器端的編程上引入了很多創新思維。 2009年 Node.js誕生 第一個形式的npm誕生 2010年 Express誕生 Socket.io誕生 2011年 npm達到1.0版本 大公司開始採用Node.js:LinkedIn, Uber Hapi誕生 2012年 采用速度非常快 2013年 第一個使用Node.js的大型網站平台:Ghost Koa誕生 2014年 大分叉:io.js是Node.js的一個重大分叉,旨在引入ES6支持並加快發展速度 2015年 Node.js基金會成立 io.js合併回Node.js npm引入私有模組 Node 4(此前曾沒有1、2、3版本的發布) 2016年 leftpad事件 Yarn誕生 Node 6 2017年 npm更加關注安全性 Node 8 - 9 HTTP/2 V8將Node納入測試套件,正式將Node作為JS引擎的目標之一,除Chrome外還有許多JS引擎 每週下載30億個npm套件 2018年 Node 10 - 11 ES模塊 ....

nodejs-hosting

在哪裡託管Node.js應用程式 Node.js應用程式可以在許多不同的地方託管,取決於您的需求。以下是您可以選擇的各種選項的列表。 我將從最簡單且受限制的選項開始列出,然後逐漸介紹更複雜且功能強大的選項。 最簡單的選項:本地隧道 即使您的IP地址是動態的,或者您在NAT下,您也可以使用本地隧道在計算機上部署您的應用程式並提供請求。 這個選項適用於快速測試、演示產品或與一小群人分享應用程式。 這方面非常好的一個工具是ngrok,它可以在所有平台上使用。您只需輸入ngrok PORT,您要公開的PORT就會進行連接。您會得到一個ngrok.io域名,但如果您支付了訂閱費用,您就可以獲得一個自定義的URL,以及更多的安全選項(請記住,您正在將您的機器開放給公共互聯網)。 另一個您可以使用的服務是localtunnel。 零配置部署 Glitch Glitch是一個遊樂場和一種比以往更快地構建應用程式並在它們自己的glitch.com子域上實時查看它們的方式。目前您不能使用自定義域名,並且有一些限制,但這對於原型開發非常有用。它看起來很有趣(這是一個加分點),並且它不是一個簡化版的環境-您擁有Node.js的所有功能,CDN、安全存儲憑證、GitHub導入/導出等等。 由FogBugz和Trello背後的公司提供(也是Stack Overflow的共同創作者之一)。 我常常在演示中使用它。 Codepen Codepen是一個令人驚奇的平台和社區。您可以創建包含多個文件的專案,並使用自定義域名部署它。 無伺服器部署 Serverless是一種發佈您的應用程式並完全不需要管理伺服器的範式,您可以將應用程式發佈為函數,它們在網絡端點上響應(也稱為FAAS-是一種“功能即服務”)。 兩個非常受歡迎的解決方案是 Serverless Framework Standard Library 它們都提供了一個抽象層,用於在基於Azure或Google Cloud的AWS Lambda和其他FAAS解決方案上發布。 PAAS PAAS代表Platform As A Service(平台即服務)。這些平台簡化了您在部署應用程式時需要擔心的很多事情。 Zeit Now Zeit是一個有趣的選項。您只需在終端機中輸入now,它就會負責部署您的應用程式。有一個帶有限制的免費版本,付費版本更強大。您將忘記有一個伺服器存在,只需部署應用程式即可。 Nanobox Nanobox Heroku Heroku是一個令人驚奇的平台。 這是一篇有關在Heroku上開始使用Node.js的很棒文章。 Microsoft Azure Azure是Microsoft的雲端產品。 查看如何在Azure上創建一個Node.js Web應用程式。 Google Cloud Platform Google Cloud是一個令人驚奇的應用程式結構。 他們有一個良好的Node.js文檔區 虛擬私有伺服器 在這一節中,您會找到一些常見的選擇,從較為用戶友好的到較少用戶友好的: Digital Ocean Linode Amazon Web Services,特別提到Amazon Elastic Beanstalk因為它可以抽象出AWS的一些複雜性。 由於它們提供了一台空的Linux機器供您使用,這些都沒有特定的教學。 VPS類別中還有更多選項,這些只是我使用過並且可能推薦的選項。 裸機 另一種解決方案是獲取一台裸機伺服器,安裝Linux發行版,將其連接到互聯網(或者像使用Vultr Bare Metal服務一樣月租一台)

nodemailer,如何將圖像嵌入電子郵件

我需要在使用 nodemailer 發送的電子郵件中嵌入圖像。 我試過使用附件的方式,但圖像卻被添加為附件。 因此,我將圖像以 base64 的形式嵌入到電子郵件正文中。 首先,我們需要添加一些引用: import fs from 'node:fs' import path from 'path' import { fileURLToPath } from 'url' const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) 我們需要這樣做是因為在 ES 模塊中,__dirname 在作用域內無效,我們必須使用 fs 的 readFileSync() 函數來引用文件,但它需要絕對路徑,而不是相對路徑。 長話短說,就是這樣。 現在讀取圖像: const imageData = fs.readFileSync(__dirname + '/image.jpg', 'binary') 將其轉換為 base64 編碼的字符串: const src = `data:image/jpg;base64,${Buffer.from( imageData, 'binary' ).toString('base64')}` 最後,將其添加到電子郵件正文中: const mailOptions = { //... html: `<img style="width:800px;" src="${src}">`, }

Node事件發射器

如何在Node中使用自定義事件 如果你在瀏覽器中使用JavaScript,你知道多數的用戶互動是透過事件處理的,像是滑鼠點擊、鍵盤按鍵、對滑鼠移動作出反應等等。 在後端,Node給了我們使用events模組來建立類似的系統的選項。 這個模組中,有一個EventEmitter類別,我們會用它來處理我們的事件。 你可以使用以下語法來初始化一個EventEmitter物件: const EventEmitter = require('events') const eventEmitter = new EventEmitter() 這個物件暴露了許多方法,其中包括on和emit。 emit方法用於觸發一個事件。 on方法用於添加一個當事件觸發時要執行的回調函數。 觸發和監聽事件 舉個例子,我們來創建一個start事件,作為一個示範,我們只是對它作出反應,並將其日誌記錄到控制台: eventEmitter.on('start', () => { console.log('started') }) 當我們執行 eventEmitter.emit('start') 事件處理函數將會被觸發,並且我們將得到控制台日誌記錄。 addListener()是on()的別名,如果你看到那樣的寫法,它們表示的是同一個意思。 將參數傳遞給事件 你可以通過將它們作為額外的參數傳遞給emit()的方式,將參數傳遞給事件處理函數: eventEmitter.on('start', (number) => { console.log(`started ${number}`) }) eventEmitter.emit('start', 23) 多個參數: eventEmitter.on('start', (start, end) => { console.log(`started from ${start} to ${end}`) }) eventEmitter.emit('start', 1, 100) 只監聽一次事件 EventEmitter物件還提供了once()方法,你可以使用它來創建一個一次性事件監聽器。 一旦該事件觸發,該監聽器就停止監聽。 例如: eventEmitter.once('start', () => { console.log(`started!`) }) eventEmitter.emit('start') eventEmitter.emit('start') //不會觸發 刪除事件監聽器 一旦你創建了一個事件監聽器,你可以使用removeListener()方法來刪除它。...

Node事件模組

Node.js的events模組提供了EventEmitter類別 events模組為我們提供了EventEmitter類別,這是在Node中處理事件的關鍵。 我在這篇完整的文章中發布了更多詳細內容,所以在這裡我僅描述API而不提供進一步的用例。 const EventEmitter = require('events') const door = new EventEmitter() 事件監聽器也使用這些事件: newListener 當監聽器被添加時 removeListener 當監聽器被移除時 以下是最常用方法的詳細說明: emitter.addListener() emitter.emit() emitter.eventNames() emitter.getMaxListeners() emitter.listenerCount() emitter.listeners() emitter.off() emitter.on() emitter.once() emitter.prependListener() emitter.prependOnceListener() emitter.removeAllListeners() emitter.removeListener() emitter.setMaxListeners() emitter.addListener() emitter.on()的別名。 emitter.emit() 觸發一個事件。按照它們註冊的順序同步調用每個事件監聽器。 emitter.eventNames() 返回一個字串陣列,表示當前EventListener上註冊的事件: door.eventNames() emitter.getMaxListeners() 獲取可以添加到EventListener對象的最大監聽器數量,默認為10,但可以通過使用setMaxListeners()增加或減少。 door.getMaxListeners() emitter.listenerCount() 獲取傳遞的事件的監聽器的數量: door.listenerCount('open') emitter.listeners() 獲取傳遞的事件的監聽器數組: door.listeners('open') emitter.off() emitter.removeListener()在Node 10中新增的別名。 emitter.on() 添加在事件觸發時調用的回調函數。 用法: door.on('open', () => { console.log('門被打開了') }) emitter.once() 添加在註冊後僅在首次觸發事件時調用的回調函數。這個回調函數只會被調用一次,後續不再調用。 const EventEmitter = require('events') const ee = new EventEmitter() ee....

Node路徑模組

Node.js的路徑模組提供了一些有用的功能來處理檔案路徑。 path模組提供了許多非常有用的功能來存取和操作檔案系統。 不需要單獨安裝它。由於它是Node的核心部分,只需透過require進行引用即可: const path = require('path') 此模組提供了path.sep來提供路徑分隔符號(在Windows上為\,在Linux和macOS上為/),以及path.delimiter提供路徑分隔符(在Windows上為;,在Linux和macOS上為:)。 以下是path的方法: path.basename() path.dirname() path.extname() path.isAbsolute() path.join() path.normalize() path.parse() path.relative() path.resolve() path.basename() 返回路徑的最後一部分。第二個參數可以過濾掉檔案的副檔名: require('path').basename('/test/something') //something require('path').basename('/test/something.txt') //something.txt require('path').basename('/test/something.txt', '.txt') //something path.dirname() 返回路徑的目錄部分: require('path').dirname('/test/something') // /test require('path').dirname('/test/something/file.txt') // /test/something path.extname() 返回路徑的副檔名部分: require('path').extname('/test/something') // '' require('path').extname('/test/something/file.txt') // '.txt' path.isAbsolute() 如果是絕對路徑則返回true: require('path').isAbsolute('/test/something') // true require('path').isAbsolute('./test/something') // false path.join() 將兩個或多個路徑部分組合起來: const name = 'flavio' require('path').join('/', 'users', name, 'notes.txt') //'/users/flavio/notes.txt' path.normalize() 當路徑包含相對位置符(.或..)或連續的斜線時,嘗試計算實際的路徑: require('path').normalize('/users/flavio/..//test.txt') ///users/test.txt path.parse() 將一個路徑解析為一個包含其組成部分的物件: root:根路徑 dir:從根路徑開始的目錄路徑 base:檔案名稱+副檔名 name:檔案名稱 ext:檔案的副檔名 範例:...

Node緩衝區

瞭解Node緩衝區是什麼,它們用於什麼,以及如何使用它們。 緩衝區是什麼? 緩衝區是一塊內存區域。與C、C++或Go等使用系統編程語言的開發人員(或任何與內存交互的程序員)相比,JavaScript開發人員對這個概念不太熟悉,因為js開發人員並不需要直接與內存交互。 它代表著在V8 JavaScript引擎之外分配的固定大小的內存塊(無法調整大小)。 您可以將緩衝區視為一個整數數組,其中每個整數表示一個字節的數據。 它是由Node的Buffer類實現的。 為什麼我們需要緩衝區? 引入緩衝區是為了幫助開發人員處理二進制數據,在傳統上,js只處理字符串而不是二進制數據。 緩衝區與流(streams)緊密相關。當流處理器接收到的數據速度比它處理的速度快時,它將數據放入緩衝區。 對於緩衝區的一個簡單的可視化是當您觀看YouTube視頻時,紅色條超出了您的視覺點:您正在比您查看數據更快地下載數據,並且您的瀏覽器將其緩衝。 如何創建一個緩衝區 使用Buffer.from(),Buffer.alloc()和Buffer.allocUnsafe()方法來創建緩衝區。 const buf = Buffer.from('Hey!') Buffer.from(array) Buffer.from(arrayBuffer[, byteOffset[, length]]) Buffer.from(buffer) Buffer.from(string[, encoding]) 您還可以通過傳遞大小來初始化緩衝區。這將創建一個1KB大小的緩衝區。 const buf = Buffer.alloc(1024) //或者 const buf = Buffer.allocUnsafe(1024) 使用緩衝區 訪問緩衝區的內容 緩衝區作為字節數組,可以像訪問數組一樣訪問。 const buf = Buffer.from('Hey!') console.log(buf[0]) //72 console.log(buf[1]) //101 console.log(buf[2]) //121 這些數字是緩衝區位置中標識字符的Unicode編碼(H => 72,e => 101,y => 121)。 您可以使用toString()方法打印緩衝區的全部內容。 console.log(buf.toString()) 请注意,如果您使用設置大小的數字初始化緩衝區,您將獲得預初始化內存的訪問權限,其中包含隨機數據,而不是一個空的緩衝區。 獲取緩衝區的長度 使用length屬性。 const buf = Buffer.from('Hey!') console.log(buf.length) 遍歷緩衝區的內容 const buf = Buffer.from('Hey!') for (const item of buf) { console....

Node檔案路徑

如何在Node中與檔案路徑互動並對其進行操作 從路徑中獲取資訊 處理路徑 系統中的每個檔案都有一個路徑。 在Linux和macOS上,路徑可能如下: /users/flavio/file.txt 而Windows電腦則不同,其結構如下: C:\users\flavio\file.txt 在應用程式中使用路徑時,需要注意這個差異。 您可以通過以下方式在文件中引入這個模組: const path = require('path') 然後就可以使用其中的方法了。 從路徑中獲取資訊 給定一個路徑,可以使用以下方法從中獲取資訊: dirname:獲取檔案的上級資料夾 basename:獲取檔案名稱部分 extname:獲取檔案擴展名 範例: const notes = '/users/flavio/notes.txt' path.dirname(notes) // /users/flavio path.basename(notes) // notes.txt path.extname(notes) // .txt 如果要獲取沒有擴展名的檔案名稱,可以將第二個引數指定給basename: path.basename(notes, path.extname(notes)) //notes 處理路徑 可以使用path.join()來結合路徑的兩個或多個部分: const name = 'flavio' path.join('/', 'users', name, 'notes.txt') //'/users/flavio/notes.txt' 可以使用path.resolve()來計算相對路徑的絕對路徑: path.resolve('flavio.txt') //'/Users/flavio/flavio.txt'(從我的家目錄執行時) 在這種情況下,Node會將/flavio.txt附加到當前工作目錄。如果您指定了第二個參數,resolve將使用第一個參數作為第二個參數的基礎: path.resolve('tmp', 'flavio.txt')//'/Users/flavio/tmp/flavio.txt'(從我的家目錄執行時) 如果第一個參數以斜線開頭,則表示它是絕對路徑: path.resolve('/etc', 'flavio.txt')//'/etc/flavio.txt' path.normalize()是另一個有用的函數,當路徑包含.、..或雙斜線等相對標識時,它將嘗試計算實際路徑: path.normalize('/users/flavio/..//test.txt') ///users/test.txt resolve和normalize都不會檢查路徑是否存在。它們只是基於它們獲得的資訊計算一個路徑。

Notion API,更新頁面的圖示表情符號

以下是使用Notion API更新Notion頁面的圖示表情符號的方法。 假設您已經初始化了Notion客戶端: import { Client } from '@notionhq/client' //... const notion = new Client({ auth: process.env.NOTION_API_KEY }) 假設頁面id存儲在page_id變量中。 然後,您可以這樣做將頁面圖示的值設置為新的表情符號: await notion.pages.update({ page_id: page_id, icon: { type: 'emoji', emoji: '✅', }, })