Day 51 (Node.js)

1.res.send()和 res.end()的差别

(1)res.write + res.end

     http.createServer(function (req, res) {
         if(results[0])[
             res.write("<html>")
             res.write("<head>")
             //...
             res.write("</html>")
             res.end();
     }

现在都直接用res.render("index.ejs",{})输出网页

(2)res.send = res.write + res.end
後来大家都直接用 send

     app.get("/", function (req, res) {
       res.send("OK, Home page....");
     }) 

2.资料库Update (档案Lab > 15_资料库_UpdateDelect)

(1)

npm install
npm start (nodemon app.js)

(2)Update
当使用者点击编辑:资料放在编辑页面上SPA(没有另跳页面)
特性:使用JS编辑(rel="modal:open"),server只给值

(3)HTML

     <!-- modal:open 另跳视窗开启 -->
     <a href="#ex1" rel="modal:open"> 
     <button  onclick="Edit(<%= item.id%>)">编辑</button></a> 
     <button onclick="Delete(<%= item.id%>)">删除</button>

(4)index.ejs > 取值

        function Edit(id) {
            $.ajax({
                url: "/detail/"+id,   
                type: "GET",
                success: function(res) {
                    var res = JSON.parse(res)
                    //res.data 指 success.data
                    //将值传递进input里头
                    $("input[name='id']").val(res.data.id)  
                    $("input[name='name']").val(res.data.name)
                    $("input[name='phone']").val(res.data.phone)
                    $("input[name='address']").val(res.data.address)
                    $("input[name='adult_mask']").val(res.data.adult_mask)
                    $("input[name='child_mask']").val(res.data.child_mask)
                },
                error: function() {
                    alert("系统错误!")
                },
            })
        }

(5)index.js > SQL语法
1.取值显示在编辑页面上,2.页面回传Success or Error

    index.get('/detail/:id([0-9]+)', function(req, res){
    var sql = `SELECT * FROM inventory WHERE id = ?;`
    var data = [req.params.id]
    // exec MySQL的引用
    db.exec(sql, data, function(results, fields) {
        if(results[0]){  //第0笔资料
            res.end(
                JSON.stringify(new Success(results[0]))
            )
        } else {
            res.end(
                JSON.stringify(new Error('no result'))
            )
        }
      })
    })

(6)response.js > Success or Error输出data(此处)或message

    class Success {
      constructor(data, message) {
        if(typeof data === 'string') {
            this.message = data
            data = null
            message = null
        }
        if(data) {
            this.data = data
        }
        if(message) {
            this.message = message
        }
        this.errno = 1
      }  
    }  

(7)编辑送出

        $('#submit').on('click', function() {
            //整理表单资料到变数
            var data = $('#form').serializeArray()  
            //form表单内资料转成阵列
            JSONData = serializeToJSON(data) 
                     
            //用post方法丢json格式的data到 /update 
            //阵列资料转Json物件 ajax才能使用
            $.ajax({
                url: "/update",  //index.js > exec方法输出
                type: "POST",
                contentType: "application/json; charset=utf-8",
                data: JSONData,

                success: function(res) {
                    var res = JSON.parse(res)
                    if(res.errno === 1) {                         
                        alert(res.message +"更新成功!")
                        location.reload()
                    } else if(res.errno === 0) {
                        alert("更新失败!")
                    }
                },
                error: function() {
                    alert("系统错误!")
                }
            })
        })

(8)response.js > Success or Error输出data或message(此处)

    class Success {
      constructor(data, message) {
        if(typeof data === 'string') {
            this.message = data
            data = null
            message = null
        }
        if(data) {
            this.data = data
        }
        if(message) {
            this.message = message
        }
        this.errno = 1
      }  
    }  

3.资料库Delect (档案Lab > 15_资料库_UpdateDelect)

(1)HTML

     <!-- modal:open 另跳视窗开启 -->
     <a href="#ex1" rel="modal:open"> 
     <button  onclick="Edit(<%= item.id%>)">编辑</button></a> 
     <button onclick="Delete(<%= item.id%>)">删除</button>

(2)index.ejs

        function Delete(id) {
            var JSONData = {"id": id}
            JSONData = JSON.stringify(JSONData)
            $.ajax({
                url: "/delete",
                type: "POST",
                contentType: "application/json; charset=utf-8",
                data: JSONData,
                success: function(res) {
                    var res = JSON.parse(res)
                    if(res.errno === 1) {
                        alert("删除成功!")
                        location.reload()
                    } else if(res.errno === 0) {
                        alert("删除失败!")
                    }
                },
                error: function() {
                    alert("系统错误!")
                }
            })
        }

(3) index.js > exec方法输出

      index.post('/delete', function(req, res){
          var body = req.body
          var sql = `DELETE FROM inventory WHERE id = ?;`
          var data = [parseInt(body.id)] //转数值
          db.exec(sql, data, function(results, fields) {
              //使用affectedRows,判断是否有被删除
              if(results.affectedRows){
                  res.end(
                            JSON.stringify(new Success('delete success'))
                  )
              } else {
                  res.end(
                      JSON.stringify(new Error('delete failed'))
                  )
              }
          })
      })

(3)response.js > Success or Error输出data或message(此处)

    class Success {
      constructor(data, message) {
        if(typeof data === 'string') {
            this.message = data
            data = null
            message = null
        }
        if(data) {
            this.data = data
        }
        if(message) {
            this.message = message
        }
        this.errno = 1
      }  
    } 

4.Bludbird (档案JavaScript > 09_promise)

(1)promise使用then的方法
https://ithelp.ithome.com.tw/upload/images/20210818/20137684VbY6QW0Bd5.jpg

(2)promise解决Callback Hell
bludbird套件使用promise解决Callback Hell(就不会曹套)

(3)promise物件

    function longTimeWork(workFine = true, errorMessage = "test") {
        return new Promise( (resolve, reject) => {   // 3.取得承诺物件
            setTimeout( () => {
                (workFine) ? resolve(200) : reject(errorMessage); 
           }, 1000);
        })
    }

(4)async + await (promise才有await)
成功//200
失败//test02

    async function usingLongTimeWork() {
        try {
            var result = await longTimeWork(workFine, "test02"); 
            console.log(result);
        }
        catch (e) {
            console.log(e); //"test"
        }
    
    }

5.Promise await + async(必要)(档案JavaScript > 09_promise)

await用处:等待时间,计算仓库剩几张票,再继续卖剩下的票
避免同时多人同时购票,且电脑有时间计算票数

(1)取得承诺物件

     function longTimeWork(workFine = true, errorMessage = "test") {
         return new Promise( (resolve, reject) => {   // 
             setTimeout( () => {
                 (workFine) ? resolve(200) : reject(errorMessage); // 5.收到,跑程序 
             }, 1000); //1000 = 1秒
         })
     }

(1-2)非同步 async + await

     async function main2() {       
         var p = await longTimeWork(true, "test"); // 2.呼叫function  ; await
         console.log(p);    //200
     }
     main2() 

(1-3)想要有 成功 与 失败 的输出分类时

     function usingLongTimeWork() {
         longTimeWork(true, "test")  // try true/false
         .then(function (e) {  // 成功时:resolve(200) ; e变数 
             console.log('ok2yoyo'+ e);  //ok2yoyo200                  
         })
         .catch(function (e) {  // 失败时:reject(errorMessage)
             console.log('ok3'+ e);
         })
     }

(2)02_AsyncAwait:(1)的综合简写 + =>函式
Promise + await (无须then 已内建)

        function longTimeWork(workFine = true, errorMessage = "test") {
            return new Promise( (resolve, reject) => {    //取得承诺物件
                setTimeout( () => {
                    (workFine) ? resolve(200) : reject(errorMessage);
                }, 1000);
            })
        }


        //想要有 成功 与 失败 的输出分类时 
        async function usingLongTimeWork() {
            try {
                //longTimeWork( true / false , "test")                      
                var result = await longTimeWork(false, "test"); 
                console.log(result);
            }
            catch (e) {
                console.log(e); //"test"
            }
        
            console.log("123")
        }

        usingLongTimeWork();

(3)03_testOnHtml (Promise + await)

      function longTimeWork(workFine = true, errorMessage = "test") {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            workFine ? resolve(200) : reject(errorMessage);
          }, 5000);
        });
      }

      async function usingLongTimeWork(isOK) {
        try {
          var result = await longTimeWork(isOK, "test");
          console.log(result);
        } catch (e) {
          console.log(e);
        }
      }

      console.log("flag A");
      usingLongTimeWork(true);   //200(五秒後出现)
      console.log("flag B");
      usingLongTimeWork(false);  //test(五秒後出现)
      console.log("flag C");

(4)非同步 async + await(总共用5秒)

    async function living() {
        var total = 0;

        var result1 = await happy(200, 2000);
        // result1 跑完才往下执行
        console.log(result1);
        var result2 = await sad(-100, 3000);
        // 等result1跑完 result2 才执行

        console.log(result2);
        total = result1 + result2;
        console.log("total:", total);
    }    

(5)同步进行 async + 变数 + await(总共用3秒)

    async function living() {
        var promise1 = happy(200, 2000);
        var promise2 = sad(-100, 3000);
        var result1 = await promise1;
        var result2 = await promise2;
       //同时进行,但等待完才将答案送到结果,所以只花3秒钟
        var total = result1 + result2;
        console.log("total:", total);
    }

(6)5进化版[,]

    async function living() {
    var promise1 = happy(200, 2000);
    var promise2 = sad(-100, 3000);

    let [result1, result2] = 
      await Promise.all([promise1, promise2]);  //需要同步进行时,塞在同一的阵列

    var total = result1 + result2;
    console.log("total:", total);
    }

(7)更偷懒 直接塞方法(省略仓库)

    async function living() {

        let [result1, result2] = 
          await Promise.all([happy(200, 2000), sad(-100, 3000)]);  //省略仓库

        var total = result1 + result2;
        console.log("total:", total);
    }

6.await使用 Demo > ticket资料夹

举例:1个商品有3个人同时购买
但刚好在同一秒钟,三个人同时点下购入,会变成3个人都交易成功
为了避免,就要使用这个方法

(1)Demo_Multi_Users(SQL_Server)
顾客买商品各一个:Demo_Multi_Users(SQL_Server) > ClientA、B、C.sql
此时会导致资料库误读,因为同时购买

    select @count = UnitsInStock from Products where ProductID = 1
    waitfor delay '00:00:15' //同时间00:00:15购买
    update Products set UnitsInStock = @count - 1 where ProductID = 1

老师用sql server,但MySQL应该也可以使用

(2)新增资料库 MySQL

    create database ticketdb default character set utf8;
    use ticketdb;
    create table concert
    (
      concertId int auto_increment not null primary key,
      concertName varchar(30),
      count int
    );
    
    insert into concert (concertName, count) values 
      ('Jody''s last conert', 1000),
      ('Jeter say good-bye', 2000);

    select * from concert;

(3) > npm start

      "scripts": {
        "start": "nodemon ./bin/www"
      },

(4) ticket.js (await + FOR UPDATE)

    await req.mysql.queryAsync("start transaction", []);  
    //交易机制SQL备份,之後rollback恢复(大家同时抢票,同时交易会同时产生订单(错误),系统出错rollback恢复,再抢一次)

    var data = await req.mysql.queryAsync("select * from concert where concertId = 1 for update", []); 
      // FOR UPDATE 锁资料锁到交易完成  
      // 多人锁定控制 更改 (票只剩一张,只能看不能下单)
      // 为了确定买票只有一个人正在进行

7. CORS - SOP同源政策

去别人的服务器抓资料

(1)通讯协定、机器名称、port号三者都必须相同才符合同源政策

(2)

    var cors = require("cors"); //引用cors物件

    const corsOptions = {
        origin: [  //把别人的服务器放进来,跟人家要资料(别人可以拒绝
            'http://www.beauty.com',
            'http://localhost',
        ],
        methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS'
    };

methods:
Create → POST
Read → GET
Update → PUT
Delete → DELETE


8.callback - function仓库

      function lab3(x, callback) {
        x += 1;
        callback(x);
      }


      lab3(20, function (value) {
        //value = 10
        alert(value);
        console.log(value);
      });

      lab3(30, (value) => {
        alert(value);
      });

      lab3(40, (value) => alert(value));

9.变数 vs 参数()

变数

     var a =1;

参数

      function lab(x) {
        x += 1;
        alert(x);
      }

      lab(10);

<<:  第38天~

>>:  Day 52 (JS_API)

Day 27 - Detect Capital

大家好,我是毛毛。ヾ(´∀ ˋ)ノ 废话不多说开始今天的解题Day~ 520. Detect Cap...

tkinter 实现台湾类股抽签程序

# -*- coding: utf-8 -*- import tkinter as tk impor...

切入的点好,就会好点

在图卡的练习中,我们学会了视觉层次的设计。 在演讲的呈现中,我们学会了言语重点的表达。 而在文章的撰...

新增表单/编辑表单,共用?或分开?

目前我们写好了一个新增的画面 需求 接下来,常见的需求是,人员的新增之後是人员的编辑。 新增用的画面...

以Postgresql为主,再聊聊资料库 PostgreSQL Event Trigger 初探

PostgreSQL Event Trigger 初探 什麽是Event Trigger? 这里的e...