2020年4月

微信小程序wx.navigateTo跳转页面并且传值


官方demo:

跳转
wx.navigateTo({
  url: 'test?id=1',
  events: {
    // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
    acceptDataFromOpenedPage: function(data) {
      console.log(data)
    },
    someEvent: function(data) {
      console.log(data)
    }
    ...
  },
  success: function(res) {
    // 通过eventChannel向被打开页面传送数据
    res.eventChannel.emit('acceptDataFromOpenerPage', { data: 'test' })
  }
})
接收
//test.js
Page({
  onLoad: function(option){
    console.log(option.query)
    const eventChannel = this.getOpenerEventChannel()
    eventChannel.emit('acceptDataFromOpenedPage', {data: 'test'});
    eventChannel.emit('someEvent', {data: 'test'});
    // 监听acceptDataFromOpenerPage事件,获取上一页面通过eventChannel传送到当前页面的数据
    eventChannel.on('acceptDataFromOpenerPage', function(data) {
      console.log(data)
    })
  }
})

webSocket 之 readyState属性


webSocket.readyState
readyState属性返回实例对象的当前状态,共有四种。
CONNECTING:值为0,表示正在连接。
OPEN:值为1,表示连接成功,可以通信了。
CLOSING:值为2,表示连接正在关闭。
CLOSED:值为3,表示连接已经关闭,或者打开连接失败。

下面是一个示例。

switch (ws.readyState) {
  case WebSocket.CONNECTING:
    // do something
    break;
  case WebSocket.OPEN:
    // do something
    break;
  case WebSocket.CLOSING:
    // do something
    break;
  case WebSocket.CLOSED:
    // do something
    break;
  default:
    // this never happens
    break;
}

golang官方读写锁案例


需要brook访问
官方链接:https://golang.org/pkg/sync/atomic/#example_Value_readMostly

读写锁

package main

import (
    "sync"
    "sync/atomic"
)

func main() {
    type Map map[string]string
    var m atomic.Value
    m.Store(make(Map))
    var mu sync.Mutex // used only by writers
    // read function can be used to read the data without further synchronization
    read := func(key string) (val string) {
        m1 := m.Load().(Map)
        return m1[key]
    }
    // insert function can be used to update the data without further synchronization
    insert := func(key, val string) {
        mu.Lock() // synchronize with other potential writers
        defer mu.Unlock()
        m1 := m.Load().(Map) // load current value of the data structure
        m2 := make(Map)      // create a new value
        for k, v := range m1 {
            m2[k] = v // copy all data from the current object to the new one
        }
        m2[key] = val // do the update that we need
        m.Store(m2)   // atomically replace the current object with the new one
        // At this point all new readers start working with the new version.
        // The old version will be garbage collected once the existing readers
        // (if any) are done with it.
    }
    _, _ = read, insert
}
定时更新
package main

import (
    "sync/atomic"
    "time"
)

func loadConfig() map[string]string {
    return make(map[string]string)
}

func requests() chan int {
    return make(chan int)
}

func main() {
    var config atomic.Value // holds current server configuration
    // Create initial config value and store into config.
    config.Store(loadConfig())
    go func() {
        // Reload config every 10 seconds
        // and update config value with the new version.
        for {
            time.Sleep(10 * time.Second)
            config.Store(loadConfig())
        }
    }()
    // Create worker goroutines that handle incoming requests
    // using the latest config value.
    for i := 0; i < 10; i++ {
        go func() {
            for r := range requests() {
                c := config.Load()
                // Handle request r using config c.
                _, _ = r, c
            }
        }()
    }
}

golang互斥锁和读写锁


1、互斥锁

其中Mutex为互斥锁,Lock()加锁,Unlock()解锁,使用Lock()加锁后,便不能再次对其进行加锁,直到利用Unlock()解锁对其解锁后,才能再次加锁.适用于读写不确定场景,即读写次数没有明显的区别,并且只允许只有一个读或者写的场景,所以该锁叶叫做全局锁。

func (m *Mutex) Unlock()用于解锁m,如果在使用Unlock()前未加锁,就会引起一个运行错误.已经锁定的Mutex并不与特定的goroutine相关联,这样可以利用一个goroutine对其加锁,再利用其他goroutine对其解锁。

互斥锁只能锁定一次,当在解锁之前再次进行加锁,便会死锁状态,如果在加锁前解锁,便会报错“panic: sync: unlock of unlocked mutex”

2、读写锁

RWMutex是一个读写锁,该锁可以加多个读锁或者一个写锁,其经常用于读次数远远多于写次数的场景.

func (rw *RWMutex) Lock()  写锁,如果在添加写锁之前已经有其他的读锁和写锁,则lock就会阻塞直到该锁可用,为确保该锁最终可用,已阻塞的 Lock 调用会从获得的锁中排除新的读取器,即写锁权限高于读锁,有写锁时优先进行写锁定
func (rw *RWMutex) Unlock() 写锁解锁,如果没有进行写锁定,则就会引起一个运行时错误

func (rw *RWMutex) RLock() 读锁,当有写锁时,无法加载读锁,当只有读锁或者没有锁时,可以加载读锁,读锁可以加载多个,所以适用于"读多写少"的场景

func (rw *RWMutex)RUnlock() 读锁解锁,RUnlock 撤销单次RLock 调用,它对于其它同时存在的读取器则没有效果。若 rw 并没有为读取而锁定,调用 RUnlock 就会引发一个运行时错误(注:这种说法在go1.3版本中是不对的,例如下面这个例子)。

读写锁的写锁只能锁定一次,解锁前不能多次锁定,读锁可以多次,但读解锁次数最多只能比读锁次数多一次,一般情况下我们不建议读解锁次数多余读锁次数


golang json字符串对象嵌套对象中的时间戳解析成科学计算数了


main:

package main

import (
    "encoding/json"
    "fmt"
    // "strings"
    // "strconv"
)
func main(){
    jsonStr := `{
        "deviceType": "CustomCategory",
        "iotId": "s1yfVm0w8HYlx2Zde7Sw000100",
        "requestId": "123",
        "productKey": "a1MRVbH5dTu",
        "gmtCreate": 1585788928824,
        "deviceName": "un00101",
        "items": {
            "Sate09": {
                "value": "19-1111-111--1",
                "time": 1585788928826
            },
            "Sate08": {
                "value": "18-1111-111--1",
                "time": 1585788928826
            },
            "Sate19": {
                "value": "10-1111-111--1",
                "time": 1585788928826
            },
            "Sate07": {
                "value": "17-1111-111--1",
                "time": 1585788928826
            },
            "Sate18": {
                "value": "9-1111-111--1",
                "time": 1585788928826
            },
            "Sate06": {
                "value": "31-1111-111--1",
                "time": 1585788928826
            },
            "Sate17": {
                "value": "8-1111-111--1",
                "time": 1585788928826
            },
            "Sate05": {
                "value": "88-1111-111--1",
                "time": 1585788928826
            },
            "Sate16": {
                "value": "7-1111-111--1",
                "time": 1585788928826
            },
            "Sate04": {
                "value": "24-1111-111--1",
                "time": 1585788928826
            },
            "Sate15": {
                "value": "6-1111-111--1",
                "time": 1585788928826
            },
            "Sate03": {
                "value": "23-0001-000-1585788922",
                "time": 1585788928826
            },
            "Sate25": {
                "value": "16-1111-111--1",
                "time": 1585788928826
            },
            "Sate14": {
                "value": "5-1111-111--1",
                "time": 1585788928826
            },
            "Sate02": {
                "value": "22-1111-111--1",
                "time": 1585788928826
            },
            "Sate24": {
                "value": "15-1111-111--1",
                "time": 1585788928826
            },
            "Sate13": {
                "value": "4-1111-111--1",
                "time": 1585788928826
            },
            "Sate01": {
                "value": "21-1111-111--1",
                "time": 1585788928826
            },
            "Sate23": {
                "value": "14-1111-111--1",
                "time": 1585788928826
            },
            "Sate11": {
                "value": "2-1111-111--1",
                "time": 1585788928826
            },
            "Sate22": {
                "value": "13-1111-111--1",
                "time": 1585788928826
            },
            "Sate10": {
                "value": "20-1111-111--1",
                "time": 1585788928826
            },
            "Sate21": {
                "value": "12-1111-111--1",
                "time": 1585788928826
            },
            "Sate20": {
                "value": "11-1111-111--1",
                "time": 1585788928826
            }
        }
    }`

    var dat map[string]interface{}
    err := json.Unmarshal([]byte(jsonStr), &dat); 
    if err == nil {
        fmt.Println("==============json str 转map=======================")
    items := dat["items"].(map[string]interface{}) //获取 items
        for k := range items{
            val := items[k].(map[string]interface{})["time"]
        fmt.Println(val) //错误的方法
            fmt.Println(int64(val.(float64))) //正确的方法

        }
    }else{
        fmt.Println(err.Error())
    }
}
错误的方法输出:
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
1.585788928826e+12
正确的方法输出:
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826
1585788928826

JavaScript使用Websocket


<script>
  function WebSocketTest() {
    if ("WebSocket" in window) {
      alert("您的浏览器支持 WebSocket!");

      // 打开一个 web socket
      var ws = new WebSocket("ws://localhost:8080/");

      ws.onopen = function () {
        // Web Socket 已连接上,使用 send() 方法发送数据
        ws.send(`{"Data":"sadddddddddd"}`);
      };

      ws.onmessage = function (evt) {
        var received_msg = evt.data;
        console.log(received_msg)
      };

      ws.onclose = function () {
        // 关闭 websocket
        alert("连接已关闭...");
      };
      
    }else {
      // 浏览器不支持 WebSocket
      alert("您的浏览器不支持 WebSocket!");
    }
  }

  WebSocketTest()
</script>

webScoket测试工具

https://www.52bd.net/usr/uploads/2020/04/751993603.html

2020-04-28T07:47:20.png
WebSocketTest.html


微信小程序怎么使用websocket


    let _this = this
    //创建websocket 连接
    let wxWebsocket = wx.connectSocket({
      url: 'ws://127.0.0.1:8080/',
      header:{
        'content-type': 'application/json',
      },
      timeout:5000,//超时时间,单位为毫秒
      success:(e)=>{//接口调用成功的回调函数
        console.log(e)
      },
      fail:(e)=>{//接口调用失败的回调函数
        console.log(e)
      },
      complete:(e)=>{//接口调用结束的回调函数(调用成功、失败都会执行)
        console.log(e)
      }
    })

    //接受消息
    wxWebsocket.onMessage((e) =>{
      console.log(e)
      _this.setData({
        testWebsocket:JSON.parse(e.data).data
      })
    })

    //监听 WebSocket 连接关闭事件
    wxWebsocket.onClose((e) =>{

    })

    //监听 WebSocket 错误事件
    wxWebsocket.onError((e) =>{

    })

    //连接打开事件
    wxWebsocket.onOpen(()=>{
      wxWebsocket.send({
        data:`{"Data":"我发送消息给你"}`,//需要发送的内容
        success:(e)=>{//接口调用成功的回调函数
          console.log(e)
        },
        fail:(e)=>{//接口调用失败的回调函数
          console.log(e)
        },
        complete:(e)=>{//接口调用结束的回调函数(调用成功、失败都会执行)
          console.log(e)
        }
      })
    })

    wxWebsocket.close({
      code:1000,//一个数字值表示关闭连接的状态号,表示连接被关闭的原因。1000(表示正常关闭连接)
      reason:"",//一个可读的字符串,表示连接被关闭的原因。这个字符串必须是不长于 123 字节的 UTF-8 文本(不是字符)。
      success:(e)=>{//接口调用成功的回调函数
        console.log(e)
      },
      fail:(e)=>{//接口调用失败的回调函数
        console.log(e)
      },
      complete:(e)=>{//接口调用结束的回调函数(调用成功、失败都会执行)
        console.log(e)
      }
    })

beego 怎么搭建websocket服务实时推送/接收数据



package controllers

import (
    "github.com/astaxie/beego"
    "github.com/gorilla/websocket"
    "log"
    "fmt"
    "net/http"
)
 

//连接的客户端,吧每个客户端都放进来
var clients = make(map[*websocket.Conn]bool) 
//广播频道(通道)
var broadcast = make(chan Message)           
// 配置升级程序(升级为websocket)
var upgrader = websocket.Upgrader{}

// 定义我们的消息对象
type Message struct {
    Data    interface{} `json:"data"`
}

func (c *SbController) WebSocketServi(){
    // 解决跨域问题(微信小程序)
    upgrader.CheckOrigin = func(r *http.Request) bool {
        return true
    }
    //升级将HTTP服务器连接升级到WebSocket协议。
    //responseHeader包含在对客户端升级的响应中
    //请求。使用responseHeader指定Cookie(设置Cookie)和
    //应用程序协商的子目录(Sec WebSocket协议)。
    //如果升级失败,则升级将向客户端答复一个HTTP错误
    ws, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
    if err != nil {
        log.Fatal(err)
    }
     defer ws.Close()

    //将当前客户端放入map中
    clients[ws] = true
    
    
    m := Message{
        Data:0,
    }
    //把消息 写入通道
    broadcast <- m

    c.EnableRender = false //Beego不启用渲染

    var s Message
    for {
        //接收客户端的消息
        err := ws.ReadJSON(&s)
        if err != nil {
            log.Printf("页面可能断开啦 ws.ReadJSON error: %v", err.Error())
            delete(clients, ws) //删除map中的客户端
            break //结束循环
        } else {
            //接受消息 业务逻辑
            fmt.Println("接受到从页面上反馈回来的信息 ", s)
        }
    }    
}


func init() {
    go handleMessages()
}

//广播推送消息
func handleMessages() {
    for {
        //读取通道中的消息
        msg := <-broadcast
        fmt.Println("clients len ", len(clients))
        //循环map客户端
        for client := range clients {
            //把通道中的消息发送给客户端
            err := client.WriteJSON(msg)
            if err != nil {
                log.Printf("client.WriteJSON error: %v", err)
                client.Close()//关闭
                delete(clients, client)//删除map中的客户端
            }
        }
    }
}