--- title: NodeJS Workshop for MFEE20 (1) tags: iii-mfee20 description: NodeJS Workshop for iii MFEE20 version: 20210919 --- # NodeJS Workshop for MFEE20 (1) Ashley (小賴) ashleylai58@gmail.com 共筆: - [Git Workshop for MFEE20](https://hackmd.io/@ashleylai/S1SJk5pMt) - [NodeJS 共筆(1)](https://hackmd.io/@ashleylai/S1p51vEmt) - [NodeJS 共筆(2)](https://hackmd.io/@ashleylai/H1mvcZtUt) - [上課範例 (Github)](https://github.com/azole/hello-node) 上課錄影檔: https://drive.google.com/drive/folders/1-bh6JHVJ0551ncXl6nbH4_WUb0C_uMbV?usp=sharing 作業繳交: https://docs.google.com/spreadsheets/d/1L9uniJq0n9u-PGADwk6IxV-oj92cwucqFZDwiBL-wWc/edit?usp=sharing 已經上線的同學可以寫一下測驗 - 9/26 測驗 https://forms.gle/vmnK9onhmi2aEeA16 - 9:20 另外,關於觀影心得,在 hello-git repo 有以 issue 的方式回覆, 同學可以去看過,看過後可以回覆或是關掉那個 issue。 --- # NodeJS NodeJS 是什麼? - 框架? - JS架構下的開發工具? 以下三個是前端 - 動畫? - 寫網頁功能? - 互動? NodeJS 一般來說:可以用 javascript 寫後端程式 到目前為止,你們寫的 JS 在哪裡被執行? --> 瀏覽器 瀏覽器可以執行 JS 是因為它內建了 JS 的執行環境 ==> NodeJS 讓你在瀏覽器以外執行 JS 的環境 JS 有兩種執行環境: - 瀏覽器 - NodeJS NodeJS 是一個程式語言? 不是! Javascript 才是程式語言 NodeJS 是框架嗎? 不是! ![](https://i.imgur.com/JcXqMC2.png) window.location ==> window object document.getElementById => html ==> 瀏覽器提供 ## 安裝方法 - 直接安裝 nodejs LTS: long-term support 長期維護版 - Current: 最新的、目前的 - Active LTS: 正在積極維護跟升級中的版本 - Maintenance LTS: 維護中的 LTS 直到生命週期結尾 - EOL: end of life - nvm: node version manager 「安裝路徑不可以出現中文字」 - mac: https://github.com/nvm-sh/nvm#install--update-script - windows: https://github.com/coreybutler/nvm-windows/releases ```bash= $ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash # 確認自己用的 shell 是哪一種後,修改相對應的設定檔 $ echo $0 # 根據 echo $0 的結果,下方選擇一個來確認 $ cat ~/.zshrc $ cat ~/.bashrc # 關掉 terminal 重新啟動 $ nvm -v ``` windows nod nodespus nvm-setup.zip ```bash= # 列出可以安裝的版本 $ nvm ls-remote 14 # windows版本 $ nvm list available # 安裝最新的 LTS $ nvm install 14.17.6 # 切換版本 $ nvm use 14.17.6 # 確認目前 node 的版本 $ node -v # 列出你電腦裡 node 的版本 $ nvm ls # windows 用 list $ nvm list # 設定預設版本 $ nvm alias default 14.17.6 ``` ## 寫第一個 nodejs 程式 1. 在 github 上建立一個 hello-node 專案,勾選建立 readme 2. 找到自己這個專案的 url,在 home 目錄下 clone 這個專案 ```bash= $ cd ~ $ git clone <url> ``` 3. 用 vscode 開啟這個專案,在專案內建立 practice 檔案夾 4. 在 practice 內建立 sum.js ```javascript= console.log("hello world!"); function sum(param) { // TODO: 請從 1 + 2 + 3 + .... + param } console.log(sum(3)); // 6 console.log(sum(6)); // 21 console.log(sum(10)); // 55 ``` 5. 測試結果 ```bash= $ cd practice $ node sum.js # 如果不切換 $ node practice/sum.js ``` 6. 測試OK,請 push 到 github,在 excel 打勾 期限: 16:45 ==9/19== 作業 - 完成 sum.js 並且推上 github -> 如果有 issue 要解 - 觀看影片 https://www.youtube.com/watch?v=DgbSc6Ys710 - 在 hello-git 建立一個 video.md 的檔案 - 在這個檔案紀錄心得/筆記 - 學習對的學習方式,事半功倍 - 這兩天上課的筆記/心得 - hello-git 的 readme.md - 複習 javascript - map, filter, indexOf, join, map, pop, push, reduce, slice, splice, sort 這幾個函式暸解一下 https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array - 箭頭函式 星期五晚上 9:00 以前 mac --> Homebrew ubuntu --> apt centOS --> yum windows --> [winget](https://zh.wikipedia.org/wiki/Windows%E7%A8%8B%E5%BA%8F%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8) 資料結構 & 演算法 - 資料結構 Data Structure (DS) 資料怎麼儲存、怎麼存取、之間的關係的時候 例如: array - 演算法 Algorithm (algo) 怎麼「有效率」解決一個題目 - 時間複雜度: 通常會希望愈快愈好 - 空間複雜度: 通常會希望用盡量少的記憶體 「用空間換取時間」 練習平台: leetcode (刷題) 梯形公式 從 1 加到 100000,重複 10000 次 SUM1: 2.289ms 從 1 加到 100,重複 10000 次 SUM1: 20.609ms ==> 在 n 很大的情況下,表現會比較好 for 迴圈的做法: 從 1 加到 100000,重複 10000 次 SUM2: 1.278s SUM2: 4.675ms ==> 在 n 比較小的情況下,表現會比較好 - 梯形公式是 O(1) 的寫法,for-loop 是 O(n) 的寫法, O(n) 時間複雜度比較高。 - 時間複雜度跟真正的執行時間,不是一定符合的 - 時間複雜度的討論通常在 n 比較大的情況下 - 寫程式之前想一下 - 當你學會用鐵鎚的時候,你會覺得全世界都是釘子 ------ NodeJS > node sum.js Ryan: web 伺服器方面的問題,研究過 apache, C, Lua, Haskell 或是 Ruby 瀏覽器大戰 netscape 瀏覽器 X Microsoft windows, IE 6 獨佔 --> firefox --> Chrome javascript 執行引擎 V8 --> 非常有效率的 JS 引擎 node 使用 chrome V8 來當作核心 - Chrome V8 - firefox SpiderMonkey - Safari: Nitro - Edge: Chakra --> V8 # JS 語言的特性 - 單執行緒: 啟動一個 process 而且裡面只有一個 thread 在執行你的程式 PHP 有處理過多執行緒? -> multiple processes ```sequence client->php process 1: req ``` ```sequence client->php process 2: req ``` NodeJS: 一個 process / single-thread -n 10000 -c 1000 Requests per second: 2862.02 [#/sec] (mean)誤差不大 Time per request: 349.403 [ms] (mean) -n 100000 -c 1000 Requests per second: 2993.87 [#/sec] (mean) Time per request: 334.016 [ms] (mean) -n 300000 -c 1000 大壓力 Requests per second: 3582.09 [#/sec] (mean)很快 Time per request: 279.167 [ms] (mean) PHP: 瘋狂開公司(很多 processes) -n 10000 -c 1000 在一萬個請求跑的數據是這樣 Requests per second: 2242.04 [#/sec] (mean)誤差不大 Time per request: 446.023 [ms] (mean) -n 100000 -c 1000在十萬個請求跑的數據是這樣 Requests per second: 2893.70 [#/sec] (mean) Time per request: 345.578 [ms] (mean) -n 300000 -c 1000大壓力 Failed requests: 58 Requests per second: 2100.17 [#/sec] (mean)很慢 Time per request: 476.152 [ms] (mean) NodeJS vs PHP - php 會有很多個 processes - 善用多核心 - context switching 很高 - swoole (PHP的框架) - NodeJS single-thread - 只有用到一個核心 (比較無法善用多核心的硬體能力) - 小壓力的情況下,其實兩者差不了太多 - 大壓力: php 通常比較有可能掛掉 **所謂的效能比較,不同的情境之下,結果可能截然不同** NodeJS 是 single-thread,他為什麼可以服務這麼多請求,而且還沒有比較慢? - 非阻塞 - 非同步IO - 事件循環 ![](https://i.imgur.com/8gKhy7d.png) 資料結構 Stack: 先進後出 (後進先出) First In Last Out (FILO) Last In First Out (LIFO) 放任務放進 stack ==> push 把任務從 stack 拿出來 ==> pop javascript array function - push 從尾端放東西 - pop 從尾端拿東西 php - array_push - array_pop 資料結構 Queue 佇列 先進先出 First In First Out (FIFO) 生產者消費者模式 生產者 --> buffer --> 消費者 (queue) call stack ![](https://i.imgur.com/CDkxhLn.png) ![](https://i.imgur.com/10XuJdB.png) ==9/26== - 複習 OS: process, thread, context switching, race condition, 生產者/消費者模式 - 資料結構: stack, queue - event loop: https://www.youtube.com/watch?v=8aGhZQkoFbQ ## OS 補充 作業系統 Operation System (OS) 編譯式: 要事先經過「編譯」 compile -> 把程式碼轉換成機器看得懂的語言 直譯式: 在執行的當下才去做轉換 ``` 硬碟 記憶體 CPU裡的register 大 <----------> 小 便宜 貴 慢 快 ``` ![](https://i.imgur.com/azCAxXO.png) I/O: input/output - 硬碟存取(開檔、讀檔) - 網路存取 I/O 相較於 CPU 運算是非常花時間 排程 scheduling: 怎麼安排 process?什麼時候可以輪到使用 CPU? Starvation: process 長期無法獲得執行的資源 Context Switching: 祐愷: CPU 弈劭: process 傳駿: process 在 CPU 控制權切換的時候,必須保存目前執行中 Process 的狀態 載入欲執行 Process 的狀態資訊 ==> 這些狀態的讀寫之間是有成本 Process --> 公司 thread --> 是公司內的工人 因為是同一間公司,所以可以共用很多資料 四個 processes 一份報告需要處理1分鐘 如果只有一個 process,請問總要處理多久? 100min 如果有四個 process: 總共約需要 25 分鐘 P0: 1~25 份報告 P1: 26~50 份報告 P2: 51~75 份報告 p3: 76-100 份報告 一個 process 然後裡面建立了 4 個 threads 每一個 thread 都處理 1/4 的工作量 ==> 總共約需要 25 分鐘 用 4 個 thread 的方式會比用 4 個 processes 更省時間 multithreading programming ((C#, Java, C++) 公司老闆 A 先請一個人就好,等有新的工作再來招募人 - 省錢 - 會比較慢 B 先請 10 個人,有工作來就讓這 10 個人去做,如果同時間超過 10 個工作,那就再找人。 - 花錢 - 比較有效率 Race Condition: 在Share Memory 溝通方式下, 共享變數的值會因為 Processes/threads 執行的順序不同而 有所不同。 - 考卷: https://forms.gle/TbtE8fznCnv2QZnx7 # XMLHttpRequst https://developer.mozilla.org/zh-TW/docs/Web/API/XMLHttpRequest 是一個物件 XML Http Request - axios https://github.com/axios/axios/blob/master/lib/adapters/xhr.js - jquery AJAX https://github.com/jquery/jquery/blob/a684e6ba836f7c553968d7d026ed7941e1a612d8/src/ajax/xhr.js#L6 XMLHttpRequest vs Fetch 金融業、航空業 ```xml= <user> <name>Ashley</name> <phone>0987654321</phone> <address>台北市XXXXXXX</address> </user> ``` ==> 86 個字元 ```json= { name: "Ashley", phone: "0987654321", address: "台北市XXXXXXX" } ``` ==> 58 個字元 ==> 用 json 格式比較節省流量 ==> 傳輸就會比較快 IPv4 IPv6 domain name server (DNS) www.pchome.com.tw <---> 210.59.230.39 255.255.255.255 255x255x255x255 作業系統、資料結構、演算法 網路概論、網路XXX member: ashleylai / xxxxx --> 驗證之後,帳號密碼都正確 - authentication 驗證 ==> 登入 驗證你是不是某個人 ==> 401 - authorization 授權 ==> 你是不是管理員?你是不是 VIP?... ==> 403 - audit 稽核(後台) ## NodeJS/JS 的特性 - JS 單執行緒 - 非阻塞 (non-block) - 非同步IO - 事件循環 event loop (stack, queue) ```java= JS 單執行緒(一人公司) --> non-blocking(不阻塞) --> 非同步 --> web api / nodejs API (外包給別人) --> event loop & task queue --> callback --> callback hell --> promise ``` ```javascript= setTimeout(() => { console.log("settimeout") }, 0); ``` ==10/3== 作業 1. ES6 常用語法 https://gretema.github.io/javascript/20200504/221423942/ 2. 理解 callback hell --> 解決方法 promise (--> async/await) - 玩弄一下 promise 範例 - 參考資料 - https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Promise - https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Using_promises 4. (optional) 網頁的背景會定時換顏色 - 每三秒換一個底色 - 總共有 7 種顏色 - 可以寫 callback 版本 - 可以寫 promise 版本 # 10/16 物件導向 vs functional language 1. PHP, C#, JAVA, C++, ... class 類別 --- new ---> 物件(object) / 實例 (instance) 強型別 ```csharp= class Member { String name; String email; Int age; // 4 bytes Member() // 建構式 function void setName(String newName) { this.name = newName; } } ``` let m1 = new Member(); // new 幫你要跟作業系統要一塊記憶體空間 // 這塊空間多大呢? 就是 Member 這麼大 m1.setName("AAA"); let m2 = new Member(); m2.setName("BBB"); 2. JavaScript: 原型式 prototype 建構式 (也只是一個 function) new 建構式([預設值]) --> 做出一個新的物件 new 跟作業系統要一塊記憶體的空間別 new Promise(執行者) 執行者也只是一個函式,會要求傳入兩個參數: (resolve, reject) ```javascript= new Promise((resolve, reject) => { // 通常這裡我們放一些非同步的工作 // 非同步工作原本可能是用 callback 來交還控制權(交還給單執行緒) // 如果成功,就會呼叫 resolve // 如果失敗,就會呼叫 reject }) ``` ## readfile // 1. new Promise // 2. 製作執行函式 // 3. 把非同步函式放進去 // 4.1 成功的地方,呼叫 resolve 把資料傳出來 // 4.2 失敗的地方,呼叫 reject 把錯誤傳出來 ```javascript= const fs = require("fs"); readFile('input.txt', (err, data) => { if (err) { console.error("發生錯誤", err); } else { console.log("正確讀到", data); } }); ``` 改寫成 promise 版本,還要使用它 # Await / Async 以下都不是正式的程式碼,只是示意 ```php= doWork("刷牙"); sleep(3); doWork("吃早餐"); sleep(5); doWork("寫功課"); sleep(3); ``` callback hell ```javascript= doWork("刷牙", (err, data) => { doWork("吃早餐", (err, data) => { doWork("寫功課", (err, data) => { // ..... }); }); }) ``` ```javascript= doWork("刷牙") .then((data) => { return new Pormise("吃早餐") }) .then((data) => { return new Pormise("寫功課") }) .then((data) => { // .... }) ``` ```javascript= doWork("刷牙"); doWork("吃早餐"); doWork("寫功課"); ``` 長得很像同步程式 await: 不是阻塞,他是「暫停」,他就有暫停的「範圍」 - 解除暫停? promise 裡的非同步工作完成時,呼叫 resolve 的時候會解除暫停,而且可以把結果傳出來 async: 告知「暫停的範圍」 ```javascript= async function main() { let data1 = await doWork("刷牙"); let data2 = await doWork("吃早餐"); let data3 = await doWork("寫功課"); } ``` Q. 錯誤處理? A: 只能自己用 try-catch 處理 ```javascript= try { // 1 // 2 -> 發生錯誤 // 3 // 4 } catch { } finally { // 不管有沒有錯誤,都會執行到的地方 } ``` # module ESM (ES Module) ```javascript= import React from "react"; ``` NodeJS 實作了 CJS (Common JS) CJS 可以寫在前端嗎? 瀏覽器是不認得的 webpack -> 幫忙把 CJS 的寫法轉成瀏覽器認得的方式 (編譯) ```javascript= const fs = require("fs"); fs.readFile(...); const { readFile } = require("fs"); readFile(...); ``` ```javascript= // module.exports = exports = {}; module.exports = {getBrand, price...} // return module.exports ``` module: 共用、封裝不想要透露的資料或者是功能 ** 注意 module.exports 跟 exports 共用記憶體的陷阱 ** 三個 package 的來源: - nodejs 內建給我們用: fs - 我們自己開發的: car, adder - 別人開發: 怎麼使用呢? nvm: node version manager npm: node package manager/management npm、yarn 都是 nodejs 的套件管理系統 ```bash= # 初始化一個專案,建立一個 package.json npm init # 安裝套件 npm install xxxx npm i xxxx # 移除 xxxx 套件 npm uninstall xxxx # 根據 package.json 來安裝套件 npm install # 查看 cowsay 總共有多少個版本 npm view cowsay versions # 檢查哪些套件是過期的 npm outdated # 查看專案裡裝了哪些套件跟他們的相依關係 npm list ``` package.json => 紀錄很多專案資料,紀錄 dependencies 下一次,只需要執行 npm install (不需要給套件名稱) npm 會去讀這個檔案夾底下的 package.json 幫你安裝相依的套件 - 這些相依的套件也會有自己的需要的相依套件 - 會一層一層裝下去 - 安裝的套件會裝去 node_modules 檔案夾裏面 Q. package.json 需要放進 github repo? A. YES Q. 如果你在 git pull 的時候,發現 package.json 檔案有異動,你應該要做什麼事? A. 要去執行 `npm install` 把 package.json 裡的異動處理一下(可能是安裝新的套件或是移除某些套件) Q. node_modules 要不要放進 github repo 裡? A. 大部分是不用,只要有 package.json 就好 semver: 主版本號.次版本號.patch版本 xx.xx.xx 1.2.3 2.0.1 主版本號: 不往前相容的更新(更新是比較大) --> 要做主版本號的更新,注意影響範圍、是否有足夠的時間修改、測試 次版本號: 可以向前相容的更新 patch號: 通常不會改變介面,通常就是修補 bug ~0.13.0: ~ 只會更新 patch 版本號 - 0.13.1 可以 - 0.14.0 不會更新 ^: 不會更改最左邊、非零數字的更新 ^1.2.3 最左邊非零是1 - 1.3.0 可以 - 1.2.4 可以 - 2.0.0 不可以 ^0.2.3 最左邊非零是2 - 0.2.4 可以 - 0.3.0 不可以 1.2.3 就是指定使用 1.2.3 ```json= { ... "dependencies": { "cowsay": "^1.2.0" } } ``` ==> 實際安裝下來會是 1.5.0 (最新的那個) ```json= { ... "dependencies": { "cowsay": "~1.1.0" } } ``` ==> 實際安裝下來會是 1.1.9 (最新的那個) ```bash= npx create-react-app xxxx ``` 無須安裝命令、就可以執行 ==10/16== 1. promise 2. async/await 3. fs.readFile - callback 版本 - 自己做了 promise 版本 4. CJS: module.exports (exports) ----> ESM - 物件的記憶體 5. npm, npx - package.json - 利用 package.json 來管理相依套件 - 以 cowsay 為例做練習 npm 跟 yarn https://polinwei.com/npm-vs-yarn/ 在作法上跟 npm/yarn 完全不同 https://pnpm.io/ 分析文章 https://zhuanlan.zhihu.com/p/377593512 ----- # 10/17 作業1: - 建立一個 crawler 分支/切換到這個分支 - 建立 crawler 檔案夾 - hello-node/crawler - 安裝 axios - 實作 axios 的 get 去證交所拿資料(promise版) - 請改成 await 版本 - push 到 github (crawler分支) 參考: https://github.com/azole/hello-node ```bash= # 建立分支 git branch crawler # 切換到 crawler 分支 git switch crawler mkdir crawler cd crawler npm init ``` 以下這個方式,只是從新的這個 commit 中移除而已 ```bash= # 會把 node_modules 整個刪掉,包括 git 中、也包括硬碟中 git rm -r node_modules # 只會從 git 中刪除,不會刪掉硬碟的 git rm -r --cached node_modules git commit -m "remove node_modules" git push ``` 利用 .gitignore 來設定不想放到 git repo 裡的檔案/檔案夾 Q. .gitignore 他自己本身要不要放進 git repo ? A. 要放 參考哪些應該放在 .gitignore https://www.toptal.com/developers/gitignore 關於 JS 的日期處理,可以考慮使用第三方套件 例如可以參考這類的文章來找有什麼可以用 https://openbase.com/categories/js/best-nodejs-date-libraries 爬蟲的進階: - 日期改成動態取得當天的日期(要處理格式) - 股票代碼紀錄在檔案中,透過讀檔案取得 - 股票代碼檔案可以有多個(可以參考 JS 的 string split 函式) 作業2: 在自己的資料庫建立好一個資料庫,並且在其中建立以下的資料表: ![](https://i.imgur.com/k2ZxSpD.png) # 存取資料庫 https://www.npmjs.com/package/mysql https://www.npmjs.com/package/mysql2 ```bash= npm i mysql ``` ```javascript= const mysql = require("mysql"); const connection = mysql.createConnection({ host: "localhost", // 本機 127.0.0.1 user: "???", password: "???", database: "???", }); connection.connect(); connection.query( "INSERT IGNORE INTO stock (stock_no, date, deal, amount, count) VALUES (?, ?, ?, ?, ?);", [stockCode, firstItem[0], firstItem[1], firstItem[2], firstItem[8]], (err, results) => { if (err) { console.error("發生錯誤", err); } else { console.log("db結果", results); } } ); ``` 作業3: https://github.com/azole/hello-node/blob/crawler/crawler/app-db.js 改成 promise/await 版本 deadline: 3:40 ***密碼等私密資料不可以傳到 github 上面去*** 像是第三方服務給你設定的 secret 不能傳上去,但是要可以設定 利用 dotenv 這個套件來處理這些設定檔 https://www.npmjs.com/package/dotenv ```javascript= require("dotenv").config(); // 利用 process.env.xxxx 來存取設定檔 const connection = mysql.createConnection({ host: process.env.DB_HOST, // 本機 127.0.0.1 port: process.env.DB_PORT, // 埠號 mysql 預設就是 3306 user: process.env.DB_USER, password: process.env.DB_PWD, database: process.env.DB_NAME, }); ``` 製作一個 .env 檔案,裡面存著所有需要的設定 Q: .env 可以放到 github repo 去? A: 當然不行,把 .env 放到 .gitignore Q: 既然 .env 不可以放到 github repo 上去,協作者(同組的同學或同事)怎麼知道有哪些設定要做? A: 建立一個檔案 .env.example,把 key 放到 .env.example 這個檔案來, 且會把 .env.example 放到 github repo 上去 ==10/17== 作業 1. 爬蟲資料儲存到 mysql 的 await 做出來 2. 改成用 dotenv 來儲存私密資料 - .env.example - 程式碼中不該出現任何密碼 3. 如何刪掉已經推上去的 commit? 4. 把 crawler 分支合併進去 main,但是不可以自己併 - 建立一個 pull request - 找同學幫你 review - 有沒有正確使用 dotenv - 程式裡面是用 process.env.xxx 來設定的 - 有提供 .env.example - 檢查程式碼是否正確 - axios 是否有用對 - 有沒有正確存到資料庫?? - 是不是用 promise/await - 排版? - 有沒有任何其他問題? deadline: 10/27 (三) 晚上 12:00 ----- # 10/29 [bluebird](http://bluebirdjs.com/docs/api-reference.html) → 不是 promise 的東西包成 promise ```Bash= $ npm i bluebird # 覆蓋原生的 promise const promise = require("bluebird") ``` -promisify (v.) → 把這個東西 promise 化 -connectAsync() -promise.all() → 放好幾個 promise / 等到最後一個做完,再做下一件事 -promise.race() → 看誰第一個做完 - node.js 世界中的套件 1. 自己開發 2. 用第三方的 3. 用內建的 - Apache / Nginx → web server - [nodemon](https://www.npmjs.com/package/nodemon) → 偵測檔案有無變動、自動重啟 - 只會改硬碟並不會讀進記憶體 → 除非重啟 node - npm -g 裝在那個版本底下 - npm init -f 初始化且使用預設 別名:預設指令(保持彈性) ![link text](https://s3.us-west-2.amazonaws.com/secure.notion-static.com/2e262b8d-cefa-4087-93ba-86b6a19e4871/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAT73L2G45O3KS52Y5%2F20211029%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20211029T034122Z&X-Amz-Expires=86400&X-Amz-Signature=31b0775d9dbe44affb0baf52555fd7977cded8bd51b3802e073f783e4e1f64a8&X-Amz-SignedHeaders=host&response-content-disposition=filename%20%3D%22Untitled.png%22) ```Bash= $ npm run dev ``` 異地備份 ![](https://s3.us-west-2.amazonaws.com/secure.notion-static.com/cec44fef-ae27-4b52-bb6d-c297232ebc86/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAT73L2G45O3KS52Y5%2F20211029%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20211029T040636Z&X-Amz-Expires=86400&X-Amz-Signature=10573e6703f720f1f0e9e784bce7f140d584a862978856d87c51275cb348ee61&X-Amz-SignedHeaders=host&response-content-disposition=filename%20%3D%22Untitled.png%22) - [SLA的系統妥善率](https://andersonwang.wordpress.com/2012/11/07/sla%E7%9A%84%E7%B3%BB%E7%B5%B1%E5%A6%A5%E5%96%84%E7%8E%87/) -> 我要賣系統,我要如何告訴別人我的穩定度 # 補充資料 ## Crash Course - https://www.youtube.com/watch?v=tpIctyqH29Q&list=PL8dPuuaLjXtNlUrzyH5r6jN9ulIgZBpdo https://crashcourse.club/category/ ## ES6 常用語法 - https://gretema.github.io/javascript/20200504/221423942/ ## JavaScript prototype - https://byvoid.com/zht/blog/javascript-object-prototype/