編程課應該怎麼製作?
編程的樂趣應來自實用主義,我大學本科第一門Java編程課,幾乎勸退了所有同學,因爲那些教學代碼不實用且無趣,一點圖形化的內容都沒有,而實用的編程課應早早展現圖形化的成果, 於是我選擇開一門前後端齊頭並進的全棧課程, 本課程將從零開始, 教授大量實用的圖形化案例, 並給出完整源碼.本文涉及到的代碼完全開源在Github,地址: https://github.com/zhaoolee/it/tree/main/src/Class001
本文是基於 Node.js 和 JavaScript的全棧編程教程, 雖然Node.js 和 JavaScript都被人稱爲js
, 編程語法也近似, 但兩者的確是兩門不同的語言;
JavaScript是前端編程語言, 運行在瀏覽器, 可以用來做各種網頁特效, 數值運算, 以及數據請求, JavaScript的獨特之處在於, 它沒有競爭對手, 瀏覽器內可以運行的編程語言就它一個, 只要學前端, 就離不開Node.js;
Node.js 是後端編程語言, 也就是傳統意義的編程語言, Node.js可以讀取本地計算機的文件, 進行極爲複雜的運算, 做機器學習, 深度學習, 與Python, C, C++, GoLang等語言算得上競爭對手, Node.js的特色是與JavaScript的語法極爲相似, 學會了JavaScript的人, 再去學習Node.js, 會顯得非常容易;
本門課程目標是培養一批會寫碼, 能整活兒的全棧工程師, 全棧工程師也可以被稱作全乾工程師, 技能豐富, 能獨立完成產品的研發, 學完這門課程, 你也可以寫出自己的小程序.
學編程, 需要讓電腦可以運行代碼, 想要運行代碼,則需要安裝編程語言的開發包。
JavaScript代碼可以在瀏覽器直接運行, 安裝Chrome瀏覽器即可.
Chrome下載地址: https://google.cn/chrome
Node.js 代碼需要從官網下載開發包並安裝
Node.js官網下載頁面
https://nodejs.org/zh-cn/download/
- Windows安裝包
https://nodejs.org/dist/v16.13.0/node-v16.13.0-x64.msi
- 通過以上鍊接, 下載安裝包, 右鍵, 安裝(也可以直接雙擊安裝)
- NEXT
- 同意條款,下一步
- 保存默認安裝位置, 下一步
默認安裝位置爲 C:\Program Files\nodejs\
- 下一步
- 下一步
- 開始安裝
- 允許更改
- 等待
- 完成
- 搜索PowerShell 並使用管理員身份打開
- 輸入
node -v
, 如果能查看到Node.js的版本, 則說明安裝成功了
以上是Windows 安裝Node.js的傳統方案,現在微軟官方推出了WSL (Windows Subsystem for Linux)方案,也就是在Windows裏安裝一個Linux子系統, 可以在Windows使用Linux中超好用的zsh工具(自動路徑補全,自動命令提示,文本多彩高亮), 效果驚豔,強烈推薦! 當你用過了zsh, 你就再也無法忍受Windows超級難用的命令行工具了。
Windows安裝 WSL教程 程序員福音!Win10下使用oh-my-zsh全攻略,讓Win10開發更順滑…
安裝好WSL後, 按照本文Linux安裝Node.js部分,直接安裝Node.js即可,只需幾行命令,方便又快捷。
另外說明一下,安裝好Linux後,我們的程序可以直接在Linux中運行,Linux和Windows相當於兩臺機器,二者有獨立的IP, 我們可以通過在Linux中運行 ifconfig | grep inet
來查看Linux的ip, 後文中默認的 localhost:3000
, 也應該修改爲 Linux的ip:3000
如果你想更多瞭解Linux命令,可以查看這個網站 Linux清單
macOS 安裝Node.js
下載安裝包: https://nodejs.org/dist/v16.13.0/node-v16.13.0.pkg
- 打開安裝包
- 繼續
- 繼續
- 同意(只能同意,不同意就不讓用)
- 繼續
- 安裝
- 驗證身份,進行安裝
- 安裝成功, 關閉對話框
- 安裝包建議留一份,重裝可以用
- 打開終端
- Linux 安裝Node.js
Linux 做編程其實是最爽的,不用考慮Windows亂七八糟的路徑問題,開源免費。
如果你追求顏值,比較推薦的Linux桌面發行版是Deepin,Deepin是一款國產Linux, 本地化做的很棒,Deepin鏡像免費下載地址 https://www.deepin.org/zh/download/ 清華大學Deepin鏡像源直接下載鏈接 https://mirrors.tuna.tsinghua.edu.cn/deepin-cd/20.2.4/deepin-desktop-community-20.2.4-amd64.iso
在Linux安裝Node.js的操作,我在Deepin上完成
- 打開終端
Linux安裝Node.js僅需幾行命令
cd /opt/
sudo wget https://nodejs.org/dist/v16.13.0/node-v16.13.0-linux-x64.tar.xz
sudo tar xvf node-v16.13.0-linux-x64.tar.xz
sudo echo "export NODE_HOME=/opt/node-v16.13.0-linux-x64" >> ~/.bashrc
sudo echo "export PATH=\$NODE_HOME/bin:\$PATH" >> ~/.bashrc
source ~/.bashrc
node -v
- 獲取安裝包並解壓安裝包
安裝VSCode
VSCode是微軟推出的一款代碼編輯器,開源免費,功能強大,Windows, macOS, Linux均有對應的版本,且功能一致。
VSCode 官網: https://code.visualstudio.com/
下載頁面 https://code.visualstudio.com/Download
下載VSCode 安裝包後,雙擊安裝即可。
- 打開VSCode軟件, 安裝中文語言包
安裝完成後,重啓VSCode即可生效
VSCode是一個神奇的軟件,它不僅可以寫代碼,還可以搞各種其妙的小插件,比如可以輸入 zhihu
搜索知乎插件並安裝
安裝成功後,即可在寫代碼累的時候,刷刷知乎,放鬆一下(職業程序員摸魚神器)
如果你是個追番達人,可以搜索插件 daily-anime, 安裝成功後,使用Alt+L組合鍵,即可開始享用
我們來寫第一段代碼
- 在VSCode中新建文件
- 保存文件到桌面
- 在HelloWorld.js 中加入以下代碼
const http = require('http');
http.createServer(function (request, response) {
// 發送 HTTP 頭部
// HTTP 狀態值: 200 : OK
// 內容類型: 純文本 text/plain
// 編碼類型: utf-8
response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
// 返回內容
let content = "來自互聯網之神的祝福\n\n";
// 循環十次,不斷增加返回內容
for(let i = 0; i < 10; i++){
content = content + "Hello World==>" + i + "\n"
}
// 發送響應數據 "Hello World"
response.end(content);
}).listen(8888);
// 終端打印如下信息
console.log('請用瀏覽器訪問 http://127.0.0.1:8888/');
- 新建終端
- 右鍵頂部的標籤,左鍵點擊複製路徑
- 輸入命令
- 按回車鍵, 運行程序
- 訪問 http://127.0.0.1:8888
Node.js 程序運行成功!
使用動態的數據源
一套完整的程序,可以分爲客戶端和服務端,客戶端與服務端通過 API (Application Programming Interface,應用程序接口, 簡稱接口)進行數據交互,很多金融雲服務商,會提供一些現成的 API 進行售賣,有些按時間付費,有些按使用(調用)次數付費,我們這裏用恆生雲交易日曆API進行一波調用演示。
API 文檔地址: https://www.hs.net/openplat-front/service/serviceDetail/983
通過文檔截圖可知,我們必填的請求參數,有三個,分別是 證券市場代號secu_market
, 開始日期 strat_date
, 結束日期 end_date
如何通過API向後端程序發起請求?
我們用恆生雲的API,就要先申請恆生雲的調用權限,於是我申請了一個免費的試用
說明:恆生雲入口 https://hs.net , 如果你也想申請 可以註冊時用我的邀請碼 FP3GUX
, 如果不申請也沒關係,我對已經請求的數據做了數據緩存,你運行我提供的程序包,即可獲得數據,學習用足夠了。
我們使用恆生雲的接口,還需要, access_token
, token_type
這兩個參數,access_token
, token_type
相當於你的臨時身份ID,而這個臨時身份ID則需要使用恆生雲提供的key和secret, 進行獲取;以上規則在 https://www.hs.net/doc/100500_200550.html 裏有詳細的說明
我這裏提供通過key和secret獲取Authorization的代碼(key和secret兩個字段我留空了,換成自己免費申請的即可)。
const https = require('https');
// key 和 secret 要通過註冊恆生雲獲取
const key = "********";
const secret = "************";
// 獲得 access_token 文檔地址 https://www.hs.net/doc/100500_200550.html
const Authorization = "Basic " + Buffer.from(key+":"+secret).toString('base64');
console.log("==Authorization==>>", Authorization);
const postData = "grant_type=client_credentials";
const token_req = https.request({
hostname: 'sandbox.hscloud.cn',
path: '/oauth2/oauth2/token',
method: "POST",
headers : {
'Authorization': Authorization,
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
},
}, (token_res)=>{
token_res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
const token_info = JSON.parse(chunk);
const access_token = token_info["access_token"];
const token_type = token_info["token_type"];
console.log('token_info==>>', token_info);
console.log('access_token==>>', access_token);
console.log('token_type==>>', token_type);
}
)})
token_req.write(postData);
token_req.end();
- 有acccess_token, 和 token_type後,我們可以開始獲取交易日接口的信息了
圖中代碼
const https = require('https');
const key = "5ac2e1ee-789e-4d6b-a52d-f533b99d6a36";
const secret = "***********";
// 查看代碼前,請仔細閱讀文檔 文檔地址 https://www.hs.net/wiki/api/983_gildataastock_v1_commontable_tadingday.html
const Authorization = "Basic " + Buffer.from(key + ":" + secret).toString('base64')
console.log("==Authorization==>>", Authorization);
const postData = "grant_type=client_credentials";
let token_req = https.request({
hostname: 'sandbox.hscloud.cn',
path: '/oauth2/oauth2/token',
method: "POST",
headers: {
'Authorization': Authorization,
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
},
}, (token_res) => {
token_res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
const token_info = JSON.parse(chunk);
const access_token = token_info["access_token"];
const token_type = token_info["token_type"]
// 開始請求
// secu_market=77 77代指美國納斯達克證券交易所 , start_data=2018-01-01 代指開始時間爲2018-01-01, end_date=2020-01-05代指結束時間爲2020-01-05
const tadingday_post_data = `secu_market=77&start_date=2018-01-01&end_date=2020-01-05`;
const tadingday_authorization = token_type + " " + access_token;
let tadingday_res_body = "";
const tadingday_req = https.request({
method: "POST",
hostname: 'sandbox.hscloud.cn',
path: '/gildataastock/v1/commontable/tadingday',
headers: {
"Authorization": tadingday_authorization,
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': tadingday_post_data.length
}
}, (tadingday_res) => {
// 由於返回的數據量過於龐大, 服務器只能將數據分段返回給我們, 我們每次收到分段都會觸發data事件, 於是我們將每次返回的數據累加起來
tadingday_res.on('data', (res_data) => {
tadingday_res_body = tadingday_res_body + res_data;
})
// 當程序觸發 end事件時, 我們將已經獲得的數據打印到終端上
tadingday_res.on('end', ()=>{
console.log(tadingday_res_body);
})
})
tadingday_req.write(tadingday_post_data);
tadingday_req.end();
});
})
token_req.write(postData);
token_req.end();
爲了能更好的展示這些數據,我們可以爲這些數據做個網頁
最終效果
我們寫代碼是爲了實現功能,而Node.js的優質工具包非常多,我們可以用很少的代碼,實現複雜的功能,爲了更好的使用和管理工具包,我們需要新建一個工程。
我們在終端輸入 node -v
, 並回車,可以看到Node.js的版本;如果我們使用 npm -v
也可以看到 npm的版本
npm是隨同Node.js一起安裝的包管理工具, npm 全稱(node.js package manage), 我們使用 which node 和which npm 可以查看到, node和npm安裝在同一個目錄
創建工程的第一步是給工程起個名字,爲了避免出現亂七八糟的編碼轉換問題,工程和工程內的文件都使用英文字符命名
我們通過命令行創建一個名爲tadingday的文件夾,並以此文件夾作爲工程目錄,進行初始化
mkdir tadingday
cd tadingday
npm init -y
在開發過程中,我們需要用到兩個軟件包
nodemon
:可以監聽文件內容變化,當文件內容變化時,自動重新運行程序,提升開發效率
express
: 大名鼎鼎的Node.js服務器工具包,支持通過中間件,爲指定文件夾直接提供http服務,可以方便地解析前端請求參數,並返回數據。
安裝nodemon和express
npm install nodemon -D
npm install express
在項目文件夾中運行以上兩行代碼,即可順利安裝 nodemon和express
安裝成功後,我們項目文件夾會多出文件 package-lock.json, 以及文件夾 node_modules,原有 package.json文件的內容也會改變;
對於node_modules和package-lock.json, 我們知道它們存在的意義就好了,即使一不小心刪除了,也能通過npm install, 重新安裝回來。
而package.json則是非常重要的文件,我們需要理解其中的配置信息,並使用nodemon自定義一些指令
- package.json重要字段解讀
爲了實現通過網頁直接輸入參數, 查詢恆生的交易日數據,我們需要使用express, 將我們以前的Node.js腳本改寫成,可以接受前端請求,返回相應數據的服務端程序;這個服務端程序不僅能將以前在終端打印的數據返回給瀏覽器,還需要將寫好的網頁返回給瀏覽器。
const https = require('https');
const express = require('express');
const app = express()
app.use(express.static('html'))
app.use(express.json()) // for parsing application/json
app.use(express.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded
const port = 3000;
const key = "*******";
const secret = "*******";
// 文檔地址 https://www.hs.net/wiki/api/983_gildataastock_v1_commontable_tadingday.html
// 示例訪問鏈接 http://localhost:3000/gildataastock/v1/commontable/tadingday?end_date=2021-03-01&start_date=2021-01-01&secu_market=77
async function get_token() {
const tadingday_authorization = await new Promise((resolve, reject) => {
const Authorization = "Basic " + Buffer.from(key + ":" + secret).toString('base64')
console.log("==Authorization==>>", Authorization);
const postData = "grant_type=client_credentials";
let token_res_data = "";
let token_req = https.request({
hostname: 'sandbox.hscloud.cn',
path: '/oauth2/oauth2/token',
method: "POST",
headers: {
'Authorization': Authorization,
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
},
}, (token_res) => {
token_res.on('data', (chunk) => {
token_res_data = token_res_data + chunk;
});
token_res.on('end', () => {
console.log(`BODY: ${token_res_data}`);
const token_info = JSON.parse(token_res_data);
const access_token = token_info["access_token"];
const token_type = token_info["token_type"]
const tadingday_authorization = token_type + " " + access_token;
console.log('==tadingday_authorization==>>', tadingday_authorization);
resolve(tadingday_authorization);
})
})
token_req.write(postData);
token_req.end();
})
return tadingday_authorization;
}
app.get('/gildataastock/v1/commontable/tadingday', async (req, res) => {
const tadingday_authorization = await get_token();
console.log('req==>>', req);
const secu_market = req.query.secu_market;
const start_date = req.query.start_date;
const end_date = req.query.end_date;
// 開始請求
const tadingday_post_data = `secu_market=${secu_market}&start_date=${start_date}&end_date=${end_date}`;
let tadingday_res_body = "";
const tadingday_req = https.request({
method: "POST",
hostname: 'sandbox.hscloud.cn',
path: '/gildataastock/v1/commontable/tadingday',
headers: {
"Authorization": tadingday_authorization,
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': tadingday_post_data.length
}
}, (tadingday_res) => {
tadingday_res.on('data', (res_data) => {
tadingday_res_body = tadingday_res_body + res_data;
})
tadingday_res.on('end', () => {
console.log(`BODY: ${tadingday_res_body}`);
tadingday_res_body = JSON.parse(tadingday_res_body);
// console.log('=res_data==>>', tadingday_res_body)
res.send(tadingday_res_body)
})
})
console.log('tadingday_post_data===>>', tadingday_post_data)
tadingday_req.write(tadingday_post_data);
tadingday_req.end();
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
運行這個服務端程序後
我們可以通過訪問
直接從瀏覽器獲取數據
這段代碼裏使用了express內置的static中間件,直接將html文件夾中的網頁內容,作爲服務端文件返回
我們訪問 http://localhost:3000/tadingday/index.html 也就能自動獲取tadingday文件夾中的index.html文件
index.html的網頁內容如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="./static/bootstrap.min.css" rel="stylesheet">
<script src="./static/jquery-3.6.0.min.js"></script>
<title>交易日批量查詢</title>
</head>
<body>
<style>
.content_info{
display: inline-block;
width: 100px;
margin-bottom: 20px;
color: #FFFFFF;
text-align: center;
}
#content{
display: flex;
justify-content: space-between;
flex-wrap: wrap
}
</style>
<script>
let params = {
start_date: "2021-06-01",
end_date : "2021-09-01",
secu_market : "71"
}
function change_start_date(start_date){
console.log('start_date:', start_date);
params.start_date = start_date;
}
function change_end_date(end_date){
console.log('end_date:', end_date);
params.end_date = end_date;
}
function change_secu_market(){
let secu_market_select_dom = document.getElementById("secu_market_select");
let selected_option_info = secu_market_select_dom.options[secu_market_select_dom.selectedIndex]
params.secu_market = selected_option_info.value
}
// 檢查參數
function check(start_date, end_date, secu_market) {
let check_pass = true;
if(start_date.length === 0){
check_pass = false;
alert("請選擇開始時間!");
}
if(check_pass && end_date.length === 0) {
check_pass = false;
alert("請選擇結束時間!");
}
if(check_pass && start_date >= end_date) {
alert("開始時間不得小於或等於結束時間,請重新選擇!");
}
if(secu_market.length === 0) {
alert("請選擇類型!")
}
return check_pass
}
// 提交請求,獲取數據
function submit(){
const check_pass = check(params.start_date, params.end_date, params.secu_market);
if(check_pass === true){
$.ajax({
url: `http://localhost:3000/gildataastock/v1/commontable/tadingday?start_date=${params.start_date}&end_date=${params.end_date}&secu_market=${params.secu_market}`,
type: "get",
success: (data, textStatus, jqXHR)=>{
console.log("data==>>", data);
let content_info = "";
data["data"].map((value)=>{
const if_trading_day = value["if_trading_day"];
const trading_date = value["trading_date"];
const background_color = if_trading_day === "是" ? "#8DC43E": "#F16421";
content_info = content_info + `<div class="content_info" style='background-color: ${background_color};'>${trading_date}</div>`
})
$('#content').html(content_info);
}
})
}
}
</script>
<div style="text-align: center; font-size: 30px;padding: 20px">交易日批量查詢</div>
<div style="display: flex;justify-content: space-between; margin: 0 20px;">
<div>
<span>開始日期</span>
<input onchange="change_start_date(value)" type='date' value="2021-06-01"/>
</div>
<div>
<span>結束日期</span>
<input onchange="change_end_date(value)" type='date' value="2021-09-01"/>
</div>
<div>
<span>選擇類型</span>
<select class="form-select" default id="secu_market_select" onchange="change_secu_market()">
<option value="71" selected>櫃檯交易市場</option>
<option value="72">香港聯交所</option>
<option value="77">美國納斯達克證券交易所</option>
<option value="83">滬深證券交易所</option>
<option value="89">銀行間債券市場</option>
</select>
</div>
<button class="btn btn-success" onclick="submit()">查詢</button>
</div>
<div id="content"></div>
</body>
</html>
這段html裏還使用了 jQuery 和BootStrap這兩個經典前端包,內容放在static文件夾中
static 可以從github下載,地址 https://github.com/zhaoolee/it/tree/main/src/Class001/tadingday/html/tadingday/static
新建一個SQLite本地數據庫,將請求數據保存到數據庫中
首先,我們需要安裝一個Node.js操作sqlite的依賴包 better-sqlite3
npm i better-sqlite3
- 在項目根目錄新建一個文件夾
db
-
通過better-sqlite3新建數據庫並創建數據表
// 初始化數據庫 const db = require('better-sqlite3')(path.join(__dirname, "..", "data", "tadingday.sqlite")); // 新建數據表 // secu_market: 證券市場 if_trading_day:是否交易日 if_week_end:是否週末 if_month_end:是否月末 if_quarter_end:是否季末 if_year_end:是否年末 trading_date:交易日期 db.exec(` CREATE TABLE IF NOT EXISTS tadingday_info ( secu_market VARCHAR(50), if_trading_day VARCHAR(10), if_week_end VARCHAR(10), if_month_end VARCHAR(10), if_quarter_end VARCHAR(10), if_year_end VARCHAR(10), trading_date VARCHAR(16), request_secu_market VARCHAR(16), PRIMARY KEY(request_secu_market, trading_date) ); `);
安裝一個sqlite數據查看插件Sqlite Viewer
安裝插件Sqlite Viewer後可以查看數據庫,數據表
在數據庫中,一行數據被稱作一條記錄, 每一列的列名被稱作字段
使用Sql往數據庫插入記錄的語法
INSERT INTO table_name (字段名1,字段名2,字段名3,...) VALUES (字段名1對應的值,字段名2對應的值,字段名3對應的值,...);
代碼思路:當請求獲得數據時,調用sava_data
函數, 將請求獲得的數據,存儲到本地sqlite數據庫中
// 往本地數據庫插入數據
const insert_tadingday_info = db.prepare(`INSERT INTO tadingday_info (
secu_market,
if_trading_day,
if_week_end,
if_month_end,
if_quarter_end,
if_year_end,
trading_date,
request_secu_market
) values (
@secu_market,
@if_trading_day,
@if_week_end,
@if_month_end,
@if_quarter_end,
@if_year_end,
@trading_date,
@request_secu_market
);`);
// 返回給前端後,存儲到數據庫
tadingday_res.on('end', () => {
console.log(`BODY: ${tadingday_res_body}`);
tadingday_res_body = JSON.parse(tadingday_res_body);
res.send(tadingday_res_body)
// 存入數據庫
tadingday_res_body["data"].map((value) => {
value['request_secu_market'] = secu_market
sava_data(value)
})
})
// 使用sqlite數據庫存儲請求來的數據
function sava_data(tadingday_info_atom) {
const { secu_market, if_trading_day, if_week_end, if_month_end, if_quarter_end, if_year_end, trading_date, request_secu_market } = tadingday_info_atom;
try {
insert_tadingday_info.run(
{
"secu_market": secu_market,
"if_trading_day": if_trading_day,
"if_week_end": if_week_end,
"if_month_end": if_month_end,
"if_quarter_end": if_quarter_end,
"if_year_end": if_year_end,
"trading_date": trading_date,
"request_secu_market": request_secu_market
}
);
} catch (e) {
// console.log(e);
}
}
在數據源失效時,查詢本地數據庫獲取數據
使用Sql往從數據庫獲取記錄的語法
SELECT 字段名(如果選擇所有字段則使用星號\*) FROM 表名 WHERE 條件;
SQL代碼思路:
選擇交易日期trading_date字段 小於結束時間end_date 並且 大於開始時間start_date 並且 證券市場代號request_secu_market 等於特定的值
select * from tadingday_info
WHERE
trading_date >= @start_date AND
trading_date <= @end_date AND
request_secu_market = @request_secu_market;`
完整代碼
// 從本地數據庫取數據
const select_tadingday_info = db.prepare(`select * from tadingday_info
WHERE
trading_date >= @start_date AND
trading_date <= @end_date AND
request_secu_market = @request_secu_market;`
);
// 從本地數據庫獲取數據
function select_data(value) {
const { start_date, end_date, request_secu_market } = value;
console.log("==從本地數據庫取數據==")
try {
const result_data = select_tadingday_info.all(
{
"start_date": start_date,
"end_date": end_date,
"request_secu_market": request_secu_market
}
);
console.log('=result_data=>>', result_data);
return result_data
} catch (e) {
// console.log(e);
}
}
運行完整工程代碼
運行方法
git clone https://github.com/zhaoolee/it.git --depth=1
cd it/src/Class001/tadingday
npm install
npm run dev004
啓動項目的小工具包
啓動項目使用了4個小工具包
nodemon的作用是監聽特定文件夾,文件內容的變化,當文件產生變化時(保存文件可觸發),重新啓動項目,讓剛剛編寫的代碼生效。
opener的作用是在瀏覽器啓動新標籤頁,打開特定url的網頁
concurrently 的作用是同時運行多個指令,我們運行004-tadingday-server-and-sqlite.js 文件時,會產生阻塞;而concurrently可以讓我們同時運行004-tadingday-server-and-sqlite.js文件和 opener打開特定頁面的指令。
wait-on 是一個判斷條件的包,我們啓用後臺服務程序會監聽3000端口;但後臺服務啓動需要一些時間,如果3000端口還未被綁定時,瀏覽器就已經開始請求,那就會出現請求失敗,而wait-on包可以幫我們做一個判斷,當3000端口被使用的時候,再使用瀏覽器打開特定頁面,這樣就不會出現打開瀏覽器白屏的情況
"scripts": {
"dev004": "concurrently 'nodemon ./src/004-tadingday-server-and-sqlite.js --watch ./' 'wait-on tcp:3000 && opener http://localhost:3000/tadingday'"
}
package.json中scripts的語法小技巧:
scripts 的指令可以非常靈活的自定義,都是鍵值對的形式,鍵爲dev004
, 後面的一長串就是值, 這個值需要使用整體引號包裹,如果內部出現子指令,則需要通過單引號包裹。
&&
符號代表了先後關係,前面一個指令執行完成了,後面的指令纔會執行。