標籤: 租車

  • 09.DRF-ModelSerializer

    四、模型類序列化器ModelSerializer

    如果我們想要使用序列化器對應的是Django的模型類,DRF為我們提供了ModelSerializer模型類序列化器來幫助我們快速創建一個Serializer類。

    ModelSerializer與常規的Serializer相同,但提供了:

    • 基於模型類自動生成一系列字段
    • 基於模型類自動為Serializer生成validators,比如unique_together
    • 包含默認的create()和update()的實現

    4.1 定義

    比如我們創建一個BookInfoSerializer

    class BookInfoSerializer(serializers.ModelSerializer):
        """圖書數據序列化器"""
        class Meta:
            model = BookInfo
            fields = '__all__'
    
    • model 指明參照哪個模型類
    • fields 指明為模型類的哪些字段生成

    我們可以在python manage.py shell中查看自動生成的BookInfoSerializer的具體實現

    >>> from booktest.serializers import BookInfoSerializer
    >>> serializer = BookInfoSerializer()
    >>> serializer
    BookInfoSerializer():
        id = IntegerField(label='ID', read_only=True)
        btitle = CharField(label='名稱', max_length=20)
        bpub_date = DateField(allow_null=True, label='發布日期', required=False)
        bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=-2147483648, required=False)
        bcomment = IntegerField(label='評論量', max_value=2147483647, min_value=-2147483648, required=False)
        image = ImageField(allow_null=True, label='圖片', max_length=100, required=False)
    

    4.2 指定字段

    4.2.1) 使用fields來明確字段,__all__表名包含所有字段,也可以寫明具體哪些字段,如

    class BookInfoSerializer(serializers.ModelSerializer):
        """圖書數據序列化器"""
        class Meta:
            model = BookInfo
            fields = ('id', 'btitle', 'bpub_date')
    

    4.2.2) 使用exclude可以明確排除掉哪些字段

    class BookInfoSerializer(serializers.ModelSerializer):
        """圖書數據序列化器"""
        class Meta:
            model = BookInfo
            exclude = ('image',)
    

    4.2.3) 默認ModelSerializer使用主鍵作為關聯字段,但是我們可以使用depth來簡單的生成嵌套表示,depth應該是整數,表明嵌套的層級數量。如:

    class HeroInfoSerializer2(serializers.ModelSerializer):
        class Meta:
            model = HeroInfo
            fields = '__all__'
            depth = 1
    

    形成的序列化器如下:

    HeroInfoSerializer():
        id = IntegerField(label='ID', read_only=True)
        hname = CharField(label='名稱', max_length=20)
        hgender = ChoiceField(choices=((0, 'male'), (1, 'female')), label='性別', required=False, validators=[<django.core.valators.MinValueValidator object>, <django.core.validators.MaxValueValidator object>])
        hcomment = CharField(allow_null=True, label='描述信息', max_length=200, required=False)
        hbook = NestedSerializer(read_only=True):
            id = IntegerField(label='ID', read_only=True)
            btitle = CharField(label='名稱', max_length=20)
            bpub_date = DateField(allow_null=True, label='發布日期', required=False)
            bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=-2147483648, required=False)
            bcomment = IntegerField(label='評論量', max_value=2147483647, min_value=-2147483648, required=False)
            image = ImageField(allow_null=True, label='圖片', max_length=100, required=False)
    

    4.2.4) 显示指明字段,如:

    class HeroInfoSerializer(serializers.ModelSerializer):
        hbook = BookInfoSerializer()
    
        class Meta:
            model = HeroInfo
            fields = ('id', 'hname', 'hgender', 'hcomment', 'hbook')
    

    4.2.5) 指明只讀字段

    可以通過read_only_fields指明只讀字段,即僅用於序列化輸出的字段

    class BookInfoSerializer(serializers.ModelSerializer):
        """圖書數據序列化器"""
        class Meta:
            model = BookInfo
            fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
            read_only_fields = ('id', 'bread', 'bcomment')
    

    4.3 添加額外參數

    我們可以使用extra_kwargs參數為ModelSerializer添加或修改原有的選項參數

    class BookInfoSerializer(serializers.ModelSerializer):
        """圖書數據序列化器"""
        class Meta:
            model = BookInfo
            fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
            extra_kwargs = {
                'bread': {'min_value': 0, 'required': True},
                'bcomment': {'min_value': 0, 'required': True},
            }
    
    # BookInfoSerializer():
    #    id = IntegerField(label='ID', read_only=True)
    #    btitle = CharField(label='名稱', max_length=20)
    #    bpub_date = DateField(allow_null=True, label='發布日期', required=False)
    #    bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=0, required=True)
    #    bcomment = IntegerField(label='評論量', max_value=2147483647, min_value=0, required=True)
    

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

    FB行銷專家,教你從零開始的技巧

  • 一起玩轉微服務(6)——通信協議如何統一

    一起玩轉微服務(6)——通信協議如何統一

    一、接口調用

    接口調用如果是遠程調用,那麼就構成了簡單的分佈式。最簡單的遠程接口實現方式是web service或rest。當然一個合理的分佈式應用不僅僅是遠程接口調用這麼簡單。還需要有負載均衡、緩存等功能。最簡單實現分佈式的技術是Rest接口,因為Rest接口可以使用現存的各種服務器,比如負載均衡服務器和緩存服務器來實現負載均衡和緩存功能。

    二、統一通信協議

    關於通信協議,不同的公司有不同的選擇,但是建議同一公司內部使用統一的通信協議,比較典型的有grpc和brpc。

    1. gRPC簡介

    gRPC是Google發布的基於HTTP 2.0傳輸層協議承載的高性能開源軟件框架,提供了支持多種編程語言的、對網絡設備進行配置和納管的方法。由於是開源框架,通信的雙方可以進行二次開發,所以客戶端和服務器端之間的通信會更加專註於業務層面的內容,減少了對由gRPC框架實現的底層通信的關注。如下圖,DATA部分即業務層面內容,下面所有的信息都由gRPC進行封裝。

     

     

    grpc是一個高性能、開源和通用的 RPC 框架,面向移動和 HTTP/2 設計。目前提供 C、Java 和 Go 語言版本,分別是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持.
    grpc基於 HTTP/2 標準設計,帶來諸如雙向流、流控、頭部壓縮、單 TCP 連接上的多復用請求等特。這些特性使得其在移動設備上表現更好,更省電和節省空間佔用。
    關於具體gRPC報文的結構,可以參考下圖:

     

     

    下面展示一下gRPC的交互過程

     

     

    1. 交換機在開啟gRPC功能后充當gRPC客戶端的角色,採集服務器充當gRPC服務器角色;
    2. 交換機會根據訂閱的事件構建對應數據的格式(GPB/JSON),通過Protocol Buffers進行編寫proto文件,交換機與服務器建立gRPC通道,通過gRPC協議向服務器發送請求消息;
    3. 服務器收到請求消息后,服務器會通過Protocol Buffers解譯proto文件,還原出最先定義好格式的數據結構,進行業務處理;
    4. 數據梳理完后,服務器需要使用Protocol Buffers重編譯應答數據,通過gRPC協議向交換機發送應答消息;
    5. 交換機收到應答消息后,結束本次的gRPC交互。

    上圖展示的是gRPC交互過程的具體流程,這也是Telemetry觸發方式其中之一,稱為Dial-out模式。簡單地說,gRPC就是在客戶端和服務器端開啟gRPC功能后建立連接,將設備上配置的訂閱數據推送給服務器端。

    2. brpc

    與grpc類似,brpc源自百度,目前支撐百度內部大約 75 萬個同時在線的實例。
    其實基於以上的幾種選擇都能夠完成高效的開發,團隊內部使用統一的標準,這樣更有利於模塊化和統一標準。
    服務間的通信是通過輕量級的web服務,使用同步的REST API進行通信。在實際的項目應用中,一般推薦在查詢的時候使用同步機制,在增刪改使用異步的方式,結合消息隊列來實現數據的操作,以保證最終的數據一致性。
    具體可以使用BRPC做如下

    1. 搭建能在一個端口支持多協議的服務, 或訪問各種服務
    2. Server能同步或異步處理請求
    3. Client支持同步、異步、半同步,或使用組合channels簡化複雜的分庫或併發訪問
    4. 通過http界面調試服務, 使用cpu, heap, contention profilers
    5. 獲得更好的延時和吞吐
    6. 把你組織中使用的協議快速地加入brpc,或定製各類組件, 包括命名服務 (dns, zk, etcd), 負載均衡 (rr, random, consistent hashing)

    三、rest API

     

     

    REST API 應為創建、檢索、更新和刪除操作使用標準 HTTP 動詞,而且應特別注意操作是否冪等。
    POST 操作可用於創建資源。POST 操作的明顯特徵是它不是冪等的。舉例而言,如果使用 POST 請求創建資源,而且啟動該請求多次,那麼每次調用后都會創建一個新的唯一資源。
    GET 操作必須是冪等的且不會產生意外結果。具體來講,帶有查詢參數的 GET 請求不應用於更改或更新信息(而應使用 POST、PUT 或 PATCH)。
    PUT 操作可用於更新資源。PUT 操作通常包含要更新的資源的完整副本,使該操作具有冪等性。
    PATCH 操作允許對資源執行部分更新。它們不一定是冪等的,具體取決於如何指定增量並應用到資源上。例如,如果一個 PATCH 操作表明一個值應從 A 改為 B,那麼它就是冪等的。如果它已啟動多次而且值已是 B,則沒有任何效果。對 PATCH 操作的支持仍不一致。例如,Java EE7 中的 JAX-RS 中沒有 @PATCH 註釋。
    DELETE 操作用於刪除資源。刪除操作是冪等的,因為資源只能刪除一次。但是,返回代碼不同,因為第一次操作將成功 (200),而後續調用不會找到資源 (204)。

     

    四、你們怎麼解決

    不同項目組之間使用的語言有可能不同,框架有可能不同,同樣的,通信協議有可能不同,你們怎麼解決的呢?

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※超省錢租車方案

    ※教你寫出一流的銷售文案?

    網頁設計最專業,超強功能平台可客製化

  • 一文梳理JavaScript中的this

    一文梳理JavaScript中的this

    最近零零碎碎看了許多關於this的文章,本着“好記性不如爛筆頭”的思想,特在這裏整理一下this有關的知識點。【長文警告!!!】

    接下來,筆者將按照以下目錄對this進行闡述:

    • this是什麼?
    • this指向
      • this在全局範圍內
      • this在對象的構造函數內
      • this在對象的方法內
      • this在簡單函數內
      • this在箭頭函數內
      • this在一個事件偵聽器內
    • this綁定規則
      • 默認綁定
      • 隱式綁定
      • 显示綁定(this修改)
      • 優先級
    • 箭頭函數

    1. this是什麼?

    this是JavaScript的一個關鍵字,但它時常矇著面紗讓人無法捉摸,許多對this不明就裡的同學,常常會有這樣的錯誤認知:

    • this在函數內指向函數自身

      •   function foo(num){
              console.log("foo: " + num);
          
              //記錄foo被調用次數
              this.count++;
          }
          foo.count = 0;
          for(let i=0; i<10; i++){
              if(i > 5){
                  foo(i);
              }
          }
          console.log(foo.count); // 0, this並沒有指向foo函數,foo.count沒有進行任何操作
        
    • this在函數內指向函數的作用域

      •   function foo(){
              var a = 2;
              this.bar();
          }
          function bar(){
              console.log(this.a);
          }
          foo();// undefined, window對象沒有bar這一屬性
        

    2. this指向

    this的指向取決於他所處的環境. 大致上,可以分為下面的6種情況:

    • this在全局範圍內
    • this在對象的構造函數內
    • this在對象的方法內
    • this在一個簡單的函數內
    • this在箭頭函數內
    • this在一個事件偵聽器內

    2.1 this在全局範圍內

    this在全局範圍內綁定什麼呢?這個相信只要學過JS,應該都知道答案。如果不知道,同學真的應該反思自己的學習態度和方法是否存在問題了。話不多說,直接上代碼,一探究竟,揭開this在全局範圍下的真面目:

    console.log(this); // Window
    

    不出意外,this在全局範圍內指向window對象()。通常, 在全局環境中, 我們很少使用this關鍵字, 因此對它也沒那麼在意. 讓我們繼續看下一個環境.

    2.2 this在對象的構造函數內

    當我們使用new創建構造函數的實例時會發生什麼呢?以這種方式調用構造函數會經歷以下四個步驟:

    • 創建一個空對象;

    • 將構造函數的作用域賦給新對象(this指向了這個新對象),繼承函數的原型;

    • 執行構造函數中的代碼;

    • 返回新對象。

    看完上面的內容,大家想必也知道this在對象的構造函數內的指向了吧!當你使用new關鍵字創建一個對象的新的實例時, this關鍵字指向這個實例 .

    舉個栗子:

    function Human (age) {
        this.age = age;
    }
    let greg = new Human(22);
    let thomas = new Human(24);
    
    console.log(greg); // this.age = 22
    console.log(thomas); // this.age = 24
    
    // answer
    Person { age:22}
    Person { age:24}
    

    2.3 this在對象方法內

    方法是與對象關聯的函數的通俗叫法, 如下所示:

    let o = {
        sayThis(){
            console.log(this);
        }
    }
    

    如上所示,在對象的任何方法內的this都是指向對象本身 .

    好了,繼續下一個環境!

    2.4 this在簡單函數內

    可能看到這裏,許多同學心裏會有疑問,什麼是簡單函數?

    其實簡單函數大家都很熟悉,就像下面一樣,以相同形式編寫的匿名函數也被認為是簡單函數(非箭頭函數)。

    function hello(){
        console.log("hello"+this);
    }
    

    這裏需要注意,在瀏覽器中,不管函數聲明在哪裡,匿名或者不匿名,只要不是直接作為對象的方法,this指向始終是window對象(除非使用call,apply,bind修改this指向)。

    舉個栗子說明一下:

    // 显示函數,直接定義在sayThis方法內,this指向依舊不變
    function simpleFunction() {
        console.log(this);
    }
    
    var o = {
        sayThis() {
            simpleFunction();
        }
    }
    
    simpleFunction(); // Window
    o.sayThis(); // Window
    
    
    // 匿名函數
    var o = {
        sayThis(){
            (function(){consoloe.log(this);})();
        }
    } 
    o.sayThis();// Window
    

    對於初學者來說,this在簡單函數內的表現時常讓他們懵逼不已,難道this不應該指向對象本身?這個問題曾經也出現在我的腦海里過,沒錯,在寫代碼時我也踩過這個坑。

    通常的,當我們要在對象方法內調用函數,而這個函數需要用到this時,我們都會創建一個變量來保存對象中的this的引用. 通常, 這個變量名稱叫做self或者that。具體說下所示:

    const o = {
        doSomethingLater() {
            const self = this;
            setTimeout(function() {
                self.speakLeet();
            }, 1000);
        },
        speakLeet() {
            console.log(`1337 15 4W350M3`);
        }
    }
    
    o.doSomethingLater(); // `1337 15 4W350M3`
    

    心細的同學可能已經發現,這裏的簡單函數沒有將箭頭函數包括在內,那麼下一個環境是什麼想必也能猜到啦,那麼現在進入下一個環境,看看this指向什麼。

    2.5 this在箭頭函數內

    和簡單函數表現不太一樣,this在箭頭函數中總是跟它在箭頭函數所在作用域的this一樣(在它直接作用域). 所以, 如果你在對象中使用箭頭函數, 箭頭函數中的this總是指向這個對象本身, 而不是指向Window.

    下面我們使用箭頭函數,重寫一下上面的案例:

    const o = {
        doSomethingLater() {
            setTimeout(() => this.speakLeet(), 1000);
        },
        speakLeet() {
            console.log(`1337 15 4W350M3`);
        }
    }
    o.doSomethingLater(); // `1337 15 4W350M3`
    

    最後,讓我們來看看最後一種環境 – 事件偵聽器.

    2.6 this在事件偵聽器內

    在事件偵聽器內, this被綁定的是觸發這個事件的元素:

    let button = document.querySelector('button');
    
    button.addEventListener('click', function() {
        console.log(this); // button
    });
    

    3. this綁定規則

    事實上,只要記住上面this在不同環境的綁定值,足以應付大部分工作。然而,好學的同學總是會忍不住想說,為什麼呢?對,為什麼this在這些情況下綁定這些值呢?學習,我們不能只知其然,而不知所以然。所以,現在就讓我們來探尋,this值獲取的真相吧。

    現在,讓我們回憶一下,在講什麼是this的時候,我們說到“this的綁定取決於他所處的環境”。這句話其實不是十分準確,準確的說,this不是編寫時綁定,而是運行時綁定。它依賴於函數調用的上下文條件this綁定和函數聲明的位置無關,反而和函數被調用的方式有關

    當一個函數被調用時,會建立一個活動記錄,也稱為執行環境。這個記錄包含函數是從何處(call-stack)被調用的,函數是 如何被調用的,被傳遞了什麼參數等信息。這個記錄的屬性之一,就是在函數執行期間將被使用的this引用。this實際上是在函數被調用時建立的一個綁定,它指向什麼是完全由函數被調用的調用點來決定的

    僅僅是規則

    現在我們將注意力轉移到調用點 如何 決定在函數執行期間this指向哪裡。

    你必須考察call-site並判定4種規則中的哪一個適用。我們將首先獨立的解釋一下這4種規則中的每一種,之後我們來展示一下如果有多種規則可以適用調用點時,它們的優先級。

    3.1 默認綁定規則

    第一種規則來源於函數調用的最常見的情況:獨立函數調用。可以認為這種this規則是在沒有其他規則適用時的默認規則。我們給它一個稱呼“默認綁定”.

    現在來看這段代碼:

    function foo(){
        console.log(this); 
    }
    var a = 2;
    demo(); // 2
    

    當foo()被調用時,this.a解析為我們的全局變量a。為什麼?因為在這種情況下,對此方法調用的this實施了 默認綁定,所以使this指向了全局對象。

    在我們的代碼段中,foo()是被一個直白的,毫無修飾的函數引用調用的。沒有其他的我們將要展示的規則適用於這裏,所以 默認綁定 在這裏適用。

    如果strict mode在這裏生效,那麼對於 默認綁定 來說全局對象是不合法的,所以this將被設置為undefined。

    'use strict'
    function foo(){
        console.log(this.a); // TypeError: Cannot read property 'a' of undefined
    }
    const a = 1;
    foo();
    
    function foo(){
    	'use strict'
        console.log(this.a); // TypeError: Cannot read property 'a' of undefined
    }
    const a = 1;
    foo();
    

    微妙的是,即便所有的this綁定規則都是完全基於調用點,如果foo()的 內容 沒有在strint mode下執行,對於 默認綁定 來說全局對象是 唯一 合法的;foo()的call-site的strict mode狀態與此無關。

    function foo(){
        console.log(this.a); 
    }
    var a = 1;
    (function(){
    	'use strict';
    	foo(); // 1
    })();
    

    注意: 在代碼中故意混用strict mode和非strict mode通常是讓人皺眉頭的。你的程序整體可能應當不是 Strict 就是非Strict。然而,有時你可能會引用與你的 Strict 模式不同的第三方包,所以對這些微妙的兼容性細節要多加小心。

    3.2 隱式綁定

    另一種要考慮的規則是:調用點是否有一個環境對象(context object),也稱為擁有者(owning)或容器(containing)對象。

    讓我們來看這段代碼:

    function foo() {
        console.log(this.a);
    }
    let o = {
        a: 2,
        foo,
    }
    o.foo(); // 2
    

    這裏,我們注意到foo函數被聲明然後作為對象o的方法,無論foo()是否一開始就在obj上被聲明,還是後來作為引用添加(如上面代碼所示),都是這個 函數 被obj所“擁有”或“包含”。這裏,調用點使用obj環境來引用函數,所以可以說 obj對象在函數被調用的時間點上“擁有”或“包含”這個 函數引用。

    當一個方法引用存在一個環境對象時,隱式綁定 規則會說:是這個對象應當被用於這個函數調用的this綁定。

    只有對象屬性引用鏈的最後一層是影響調用點的。比如:

    function foo(){
        console.log(this.a);
    }
    
    var obj1 = {
        a:2,
        obj2:obj2
    };
    var obj2 = {
        a:42,
        foo:foo
    };
    obj1.obj2.foo(); // 42
    

    隱式綁定的隱患

    當一個 隱含綁定丟失了它的綁定,這通常意味着它會退回到 默認綁定, 根據strict mode的狀態,結果不是全局對象就是undefined。

    下面來看這段代碼:

    function foo(){
        console.log(this.a);
    }
    
    var obj = {
        a:2,
        foo
    };
    var bar = obj.foo;
    var a = "Global variable";
    bar(); // "Global variable"
    

    儘管bar似乎是obj.foo的引用,但實際上它只是另一個foo自己的引用而已。另外,起作用的調用點是bar(),一個直白,毫無修飾的調用,因此 默認綁定 適用於這裏。

    這種情況發生的更加微妙,更常見,更意外的方式,是當我們考慮傳遞一個回調函數時:

    function foo(){
        console.log(this.a);
    }
    
    function doFoo(fn){
    	fn();
    }
    
    var obj = {
        a:2,
        foo,
    };
    var a = "Global variable";
    dooFoo(obj.foo); // "Global variable"
    

    參數傳遞僅僅是一種隱含的賦值,而且因為我們在傳遞一個函數,它是一個隱含的引用賦值,所以最終結果和我們前一個代碼段一樣。同樣的,語言內建,如setTimeout也一樣,如下所示

    function foo(){
        console.log(this.a);
    }
    
    var obj = {
        a:2,
        foo,
    };
    var a = "Global variable";
    setTimeout(obj.foo, 100); // "Global variable"
    

    把這個粗糙的setTimeout()假想實現當做JavaScript環境內建的實現的話:

    function setTimeout(fn, delay){
        // 等待delay毫秒
        fn();
    }
    

    正如我們看到的, 隱含綁定丟失了它的綁定是十分常見的,不管哪一種意外改變this的方式,你都不能真正地控制你的回調函數引用將如何被執行,所以你(還)沒有辦法控制調用點給你一個故意的綁定。但是我們可以使用显示綁定強行固定this。

    3.3 显示綁定

    我們看到隱含綁定,需要我們不得不改變目標對象使它自身包含一個對函數的引用,而後使用這個函數引用屬性來間接地(隱含地)將this綁定到這個對象上。

    但是,如果你想強制一個函數調用使用某個特定對象作為this綁定,而不在這個對象上放置一個函數引用屬性呢?

    js有提供call()、apply()方法,ES5中也提供了內置的方法 Function.prototype.bind,可以引用一個對象時進行強制綁定調用。

    考慮這段代碼:

    function foo(){
        console.log(this.a);
    }
    var obj = {
        a:2,
    };
    foo.call(obj); // 2
    

    通過foo.call(..)使用 明確綁定 來調用foo,允許我們強制函數的this指向obj。

    如果你傳遞一個簡單原始類型值(string,boolean,或 number類型)作為this綁定,那麼這個原始類型值會被包裝在它的對象類型中(分別是new String(..),new Boolean(..),或new Number(..))。這通常稱為“boxing(封箱)”。

    注意: 就this綁定的角度講,call(..)和apply(..)是完全一樣的。它們確實在處理其他參數上的方式不同,但那不是我們當前關心的。

    單獨依靠call和apply,仍然可能出現函數“丟失”自己原本的this綁定,或者被第三方覆蓋等問題。

    但有一個技巧可以避免出現這些問題

    考慮這段代碼:

    function foo(){
        console.log(this.a);
    }
    var obj = {
    	a:2
    };
    var bar = function(){
    	foo.call(obj);
    }
    bar(); // 2
    setTimeout(bar, 100); // 2
    bar.call(window); // 2
    

    我們創建了一個函數bar(),在它的內部手動調用foo.call(obj),由此強制this綁定到obj並調用foo。無論你過後怎樣調用函數bar,它總是手動使用obj調用foo。這種綁定即明確又堅定,該方法被開發者稱為 硬綁定(显示綁定的變種)(hard binding)

    用硬綁定將一個函數包裝起來的最典型的方法,是為所有傳入的參數和傳出的返回值創建一個通道:

    function foo(something){
        console.log(this.a, something);
        return this.a + something;
    }
    var obj = {
        a:2
    };
    var bar = function() {
        return foo.apply(obj, arguments);
    }
    var b = bar(3);
    console.log(b); //  5
    

    另一種表達這種模式的方法是創建一個可復用的幫助函數:

    function foo(something){
        console.log(this.a, something);
        return this.a + something;
    }
    
    function bind(fn, obj){
        return function(){
            return fn.apply(obj, arguments);
        };
    }
    
    var obj = { a:2};
    var bar = bind(foo, obj);
    var b = bar(3);
    console.log(b); // 5
    

    由於 硬綁定 是一個如此常用的模式,它已作為ES5的內建工具提供,即前文提到的Function.prototype.bind:

    function foo(something){
        console.log(this.a, something);
        return this.a + something;
    }
    var obj = { a:2};
    var bar = foo.bind(obj);
    var b = bar();
    cobsole.log(b); // 5
    
    

    bind(..)返回一個硬編碼的新函數,它使用你指定的this環境來調用原本的函數。

    注意: 在ES6中,bind(..)生成的硬綁定函數有一個名為.name的屬性,它源自於原始的 目標函數(target function)。舉例來說:bar = foo.bind(..)應該會有一個bar.name屬性,它的值為”bound foo”,這個值應當會显示在調用棧軌跡的函數調用名稱中。

    3.4new 綁定

    第四種也是最後一種this綁定規則

    當在函數前面被加入new調用時,也就是構造器調用時,下面這些事情會自動完成:

    • 一個全新的對象會憑空創建(就是被構建)
    • 這個新構建的對象會被接入原形鏈([[Prototype]]-linked)
    • 這個新構建的對象被設置為函數調用的this綁定
    • 除非函數返回一個它自己的其他 對象,這個被new調用的函數將 自動 返回這個新構建的對象。

    考慮這段代碼:

    function foo(a){
        console.log(this.a);
    }
    var bar = new foo(2);
    console.log(bar.a); // 2
    

    通過在前面使用new來調用foo(..),我們構建了一個新的對象並這個新對象作為foo(..)調用的this。 new是函數調用可以綁定this的最後一種方式,我們稱之為 new綁定(new binding)。

    3.5 優先級

    • new綁定
    • 显示綁定
    • 隱式綁定
    • 默認綁定(嚴格模式下會綁定到undefined)

    4. 箭頭函數

    箭頭函數並非使用function關鍵字進行定義,而是通過所謂的“大箭頭”操作符:=>,所以不會使用上面所講解的this四種標準規範,箭頭函數從封閉它的(function或global)作用域採用this綁定,即箭頭函數會繼承自外層函數調用的this綁定。

    執行 fruit.call(apple)時,箭頭函數this已被綁定,無法再次被修改。

    function fruit(){
        return () => {
            console.log(this.name);
        }
    }
    var apple = {
        name: '蘋果'
    }
    var banana = {
        name: '香蕉'
    }
    var fruitCall = fruit.call(apple);
    fruitCall.call(banana); // 蘋果
    

    5. 小結

    this是JavaScript的一個關鍵字,this不是編寫時綁定,而是運行時綁定。它依賴於函數調用的上下文條件。this綁定和函數聲明的位置無關,反而和函數被調用的方式有關。為執行中的函數判定this綁定需要找到這個函數的直接調用點。找到之後,4種規則將會以 這個 優先順序施用於調用點:

    • 被new調用?使用新構建的對象。
    • 被call或apply(或 bind)調用?使用指定的對象。
    • 被持有調用的環境對象調用?使用那個環境對象。
    • 默認:strict mode下是undefined,否則就是全局對

    與這4種綁定規則不同,ES6的箭頭方法使用詞法作用域來決定this綁定,這意味着它們採用封閉他們的函數調用作為this綁定(無論它是什麼)。它們實質上是ES6之前的self = this代碼的語法替代品。

    參考文章:

    深入理解JavScript中的this

    詳解JavaScript中的this

    你不懂this:豁然開朗

    你不懂this:this是什麼?

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • MOJITO 發布一周,爬一波彈幕分析下

    MOJITO 發布一周,爬一波彈幕分析下

    MOJITO

    最近一直啥都沒寫,追個熱點都趕不上熱乎的,鄙視自己一下。

    周董的新歌 「MOJITO」 發售(6 月 12 日的零點)至今大致過去了一周,翻開 B 站 MV 一看,播放量妥妥破千萬,彈幕破十萬,這人氣還真是杠杠的。

    說實話, 「MOJITO」 這個名字對我來講有點超綱了,第一次見到完全不知道啥意思。

    不過問題不大,沒有什麼是百度解決不了的,如果有,那就再加一個知乎。

    MOJITO 的中文名是莫吉托,百度百科上是這麼介紹莫吉托的:

    莫吉托(Mojito)是最有名的朗姆調酒之一。起源於古巴。傳統上,莫吉托是一種由五種材料製成的雞尾酒:淡朗姆酒、糖(傳統上是用甘蔗汁)、萊姆(青檸)汁、蘇打水和薄荷。最原始的古巴配方是使用留蘭香或古巴島上常見的檸檬薄荷。萊姆(青檸)與薄荷的清爽口味是為了與朗姆酒的烈性相互補,同時也使得這種透明無色的調酒成為夏日的熱門飲料之一。這種調酒有着相對低的酒精含量(大約10%)。

    酒精度數在 10% 左右的話,姑且可以認為一種飲料吧。

    當然,如果要開車的話就不能把 MOJITO 當成飲料了,酒精含量再低那也是酒精。

    整個 MV 我翻來覆去的看了好幾遍, 「MOJITO」 這個東西除了在歌詞和名字中有出現,在 MV 當中一次都沒出現,毫無存在感。

    爬取 B 站彈幕

    彈幕數據的爬取比較簡單,我就不一步一步的抓請求給各位演示了,注意下面這幾個請求連接:

    彈幕請求地址:

    https://api.bilibili.com/x/v1/dm/list.so?oid=XXX
    
    https://comment.bilibili.com/XXX.xml
    

    第一個地址由於 B 站的網頁做了更換,現在在 Chrome 工具的 network 裏面已經找不到了,不過還可以用,這個是我之前找到的。

    第二個地址來源於百度,我也不知道各路大神是從哪找出來這個地址的,供參考吧。

    上面這兩個彈幕地址實際上都需要一個叫 oid 的東西,這個 oid 獲取方式如下:

    首先可以找到一個目錄頁接口:

    https://api.bilibili.com/x/player/pagelist?bvid=XXX&jsonp=jsonp
    

    這個接口也是來源於 Chrome 的 network ,其中 bvid 這個參數來源於視頻地址,比如周董的這個 「MOJITO」 的 MV ,地址是 https://www.bilibili.com/video/BV1PK4y1b7dt ,那麼這個 bvid 的值就是最後那一部分 BV1PK4y1b7dt

    接下來在 https://api.bilibili.com/x/player/pagelist?bvid=BV1PK4y1b7dt&jsonp=jsonp 這個接口中,我們可以看到返回的 json 參數,如下:

    {
        "code":0,
        "message":"0",
        "ttl":1,
        "data":[
            {
                "cid":201056987,
                "page":1,
                "from":"vupload",
                "part":"JAY-MOJITO_完整MV(更新版)",
                "duration":189,
                "vid":"",
                "weblink":"",
                "dimension":{
                    "width":1920,
                    "height":1080,
                    "rotate":0
                }
            }
        ]
    }
    

    注意:由於這個 MV 只有一個完整的視頻,所以這裏只有一個 cid ,如果一個視頻是分不同小節發布的,這裏就會有多個 cid ,不同的 cid 代表不同的視頻。

    當然,這裏的 cid 就是我們剛才想找的那個 oid ,把這個 cid 拼到剛才的鏈接上,可以得到 https://api.bilibili.com/x/v1/dm/list.so?oid=201056987 這樣一個地址,然後輸入到瀏覽器中,可以看到彈幕的返回數據,是一個 xml 格式的文本。

    源代碼如下:

    import requests
    import re
    
    # 獲取 cid
    res = requests.get("https://api.bilibili.com/x/player/pagelist?bvid=BV1PK4y1b7dt&jsonp=jsonp")
    cid = res.json()['data'][0]['cid']
    
    # 將彈幕 xml 通過正則取出,生成 list
    danmu_url = f"https://api.bilibili.com/x/v1/dm/list.so?oid={cid}"
    result = requests.get(danmu_url).content.decode('utf-8')
    pattern = re.compile('<d.*?>(.*?)</d>')
    danmu_list = pattern.findall(result)
    
    # 將彈幕 list 保存至 txt 文件
    with open("dan_mu.txt", mode="w", encoding="utf-8") as f:
        for item in danmu_list:
            f.write(item)
            f.write("\n")
    

    這裏我將獲取到的彈幕保存在了 dan_mu.txt 文件中,方便後續分析。

    繪製詞雲圖

    第一步先將剛才保存在 dan_mu.txt 文件中的彈幕讀取出來,放到了一個 list 當中:

    # 讀取彈幕 txt 文件
    with open("dan_mu.txt", encoding="utf-8") as f:
        txt = f.read()
    danmu_list = txt.split("\n")
    

    然後使用分詞工具對彈幕進行分詞,我這裏使用的分詞工具是最好的 Python 中文分詞組件 jieba ,沒有安裝過 jieba 的同學可以使用以下命令進行安裝:

    pip install jieba
    

    使用 jieba 對剛才獲得的彈幕 list 進行分詞:

    # jieba 分詞
    danmu_cut = [jieba.lcut(item) for item in danmu_list]
    

    這樣,我們獲得了分詞后的 danmu_cut ,這個同樣是一個 list 。

    接着我們對分詞后的 danmu_cut 進行下一項操作,去除停用詞:

    # 獲取停用詞
    with open("baidu_stopwords.txt",encoding="utf-8") as f:
        stop = f.read()
    stop_words = stop.split()
    
    # 去掉停用詞后的最終詞
    s_data_cut = pd.Series(danmu_cut)
    all_words_after = s_data_cut.apply(lambda x:[i for i in x if i not in stop])
    

    這裏我引入了一個 baidu_stopwords.txt 文件,這個文件是百度停用詞庫,這裏我找到了幾個常用的中文停用詞庫,來源: https://github.com/goto456/stopwords 。

    詞表文件 詞表名
    baidu_stopwords.txt 百度停用詞表
    hit_stopwords.txt 哈工大停用詞表
    scu_stopwords.txt 四川大學機器智能實驗室停用詞庫
    cn_stopwords.txt 中文停用詞表

    這裏我使用的是百度停用詞表,大家可以根據自己的需要使用,也可以對這幾個停用詞表先做整合后再使用,主要的目的就是去除一些無需關注的詞,上面這幾個停用詞庫我都會提交到代碼倉庫,有需要的自取。

    接着我們統計去除停用詞后的詞頻:

    # 詞頻統計
    all_words = []
    for i in all_words_after:
        all_words.extend(i)
    word_count = pd.Series(all_words).value_counts()
    

    最後一步就是生成我們的最終結果,詞雲圖:

    wordcloud.WordCloud(
        font_path='msyh.ttc',
        background_color="#fff",
        max_words=1000,
        max_font_size=200,
        random_state=42,
        width=900,
        height=1600
    ).fit_words(word_count).to_file("wordcloud.png")
    

    最終結果就是下面這個:

    從上面這個詞雲圖中可以看到,粉絲對「MOJITO」這首歌是真愛啊,出現頻率最高的就是 啊啊啊 還有

    當然哈,這個 也有可能是說 MV 當中那台騷氣十足的粉色的老爺車。

    還有一個出現頻率比較高的是 爺青回 ,我估計這個意思應該是 爺的青春回來啦 ,確實,周董伴隨着我這個年齡段的人一路走來,做為一位 79 年的人現在已經是 41 歲的「高齡」了,回首往昔,讓人唏噓不已。

    當年一首 「雙節棍」 火遍了中華大地,大街上的音像店整天都在循環這幾首歌,在學校上學的我這一代人,基本上是人人都能哼兩句,「快使用雙截棍,哼哼哈嘿」成了我們這一代人共有的回憶。

    智能情感傾向分析

    我們還可以對彈幕進行一次情感傾向分析,這裏我使用的是 「百度 AI 開放平台」 的情感傾向分析接口。

    百度 AI 開放平台文檔地址:https://ai.baidu.com/ai-doc/NLP/zk6z52hds

    首先是根據文檔接入 「百度 AI 開放平台」 ,獲取 access_token ,代碼如下:

    # 獲取 Baidu API access_token
    access_token_url = f'https://aip.baidubce.com/oauth/2.0/token?grant_type={grant_type}&client_id={client_id}&client_secret={client_secret}&'
    
    res = requests.post(access_token_url)
    
    access_token = res.json()['access_token']
    
    # 通用情感接口
    # sentiment_url = f'https://aip.baidubce.com/rpc/2.0/nlp/v1/sentiment_classify?charset=UTF-8&access_token={access_token}'
    # 定製化情感接口
    sentiment_url = f'https://aip.baidubce.com/rpc/2.0/nlp/v1/sentiment_classify_custom?charset=UTF-8&access_token={access_token}'
    

    百度 AI 開放平台有兩個情感分析接口,一個是通用的,還有一個是定製化的,我這裏使用的是經過訓練的定製化的接口,如果沒有定製化的接口,使用通用的接口也沒有問題。

    上面使用到的 grant_typeclient_idclient_secret 這幾個參數,大家註冊一下就能得到, 「百度 AI 開放平台」 上的這些接口都有調用數量的限制,不過我們自己使用已經足夠了。

    然後讀取我們剛才保存的彈幕文本:

    with open("dan_mu.txt", encoding="utf-8") as f:
        txt = f.read()
    danmu_cat = txt.split("\n")
    

    在調用接口獲得情感傾向之前,我們還需要做一件事情,對彈幕進行一次處理,因為彈幕中會有一些 emoji 表情,而 emoji 直接請求百度的接口會返回錯誤,這裏我使用另一個工具包對 emoji 表情進行處理。

    首先安裝工具包 emoji :

    pip install emoji
    

    使用是非常簡單的,我們對彈幕數據使用 emoji 進行一次處理:

    import emoji
    
    with open("dan_mu.txt", encoding="utf-8") as f:
        txt = f.read()
    danmu_list = txt.split("\n")
    
    for item in danmu_list:
        print(emoji.demojize(item))
    

    我們的彈幕數據中是有這樣的 emoji 表情的:

    
    
    # 處理后:
    :red_heart::red_heart::red_heart::red_heart::red_heart::red_heart::red_heart:
    

    然後,我們就可以調用百度的情感傾向分析接口,對我們的彈幕數據進行分析了:

    # 情感計數器
    optimistic = 0
    neutral = 0
    pessimistic = 0
    
    for danmu in danmu_list:
        # 因調用 QPS 限制,每次調用間隔 0.5s
        time.sleep(0.5)
        req_data = {
            'text': emoji.demojize(danmu)
        }
        # 調用情感傾向分析接口
        if len(danmu) > 0:
            r = requests.post(sentiment_url, json = req_data)
            print(r.json())
            for item in r.json()['items']:
                if item['sentiment'] == 2:
                    # 正向情感
                    optimistic += 1
                if item['sentiment'] == 1:
                    # 中性情感
                    neutral += 1
                if item['sentiment'] == 0:
                    # 負向情感
                    pessimistic += 1
    
    print('正向情感:', optimistic)
    print('中性情感:', neutral)
    print('負向情感:', pessimistic)
    
    attr = ['正向情感','中性情感','負向情感']
    value = [optimistic, neutral, pessimistic]
    
    c = (
        Pie()
        .add("", [list(attr) for attr in zip(attr, value)])
        .set_global_opts(title_opts=opts.TitleOpts(title="「MOJITO」彈幕情感分析"))
        .render("pie_base.html")
    )
    

    最後的結果圖長這樣:

    從最後的結果上來看,正向情感佔比大約在 2/3 左右,而負向情感只有不到 1/4 ,看來大多數人看到周董的新歌還是滿懷激動的心情。

    不過這個數據不一定準確,最多可以做一個參考。

    源代碼

    需要源代碼的同學可以在公眾號後台回復「MOJITO」獲取。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※超省錢租車方案

    ※別再煩惱如何寫文案,掌握八大原則!

    ※回頭車貨運收費標準

    ※教你寫出一流的銷售文案?

    FB行銷專家,教你從零開始的技巧

  • 樂視傳財務危機,將以2.6億美元賣矽谷土地

    樂視傳財務危機,將以2.6億美元賣矽谷土地

    中國樂視控股(LeEco Holdings)原本野心勃勃,要成為下一個中國版的特斯拉(Tesla Inc.),但最近卻陷入資金短缺困境,剛剛外媒傳出,樂視打算拋售不到一年前從雅虎(Yahoo Inc.)手中購入的矽谷土地,以解燃眉之急。

    路透社17日引述未具名消息人士報導(見此),樂視為了償還對供應商與商業夥伴欠下的大筆債務,決定以2.6億美元的代價,把矽谷土地賣給沒沒無名的中國地產開發商正中置業集團(Genzon Group),價碼比去(2016)年6月購入時多出1,000萬美元。正中置業則確認,的確在跟樂視洽談購買土地的相關事宜。

    消息並透露,樂視在矽谷的辦公室大舉裁員,估計員工數量已經大砍一半以上。

    樂視執行長賈躍亭甫於去年11月在一份給員工的信中坦承,公司因為擴張速度過快,不幸陷入資金短缺困境。然而,賈躍亭在寫出這封信函的一個月前,才剛在舊金山宣布要在矽谷打造第一座北美總部;他當時說,北美總部估計會聘用12,000名員工。

    賈躍亭曾在1月說,樂視的財務問題,可在3-4個月內解決。在他說完不久,地產商融創中國隨即對樂視投資了22億美元,但投資的對象卻是樂視的娛樂部門,而非燒錢嚴重的汽車製造部門。樂視在美國是與Faraday Future攜手開發豪華電動車,Faraday是賈躍亭出資控股的新創公司。

    據Business Insider 1月的採訪發現,Faraday已然在崩解之中,從去年春季後,已有超過半打的資深主管離職,全球執行長更在重要消費電子展(CES)前夕打包走人。

    知情人士形容Faraday組織結構、中美兩地的營運一團混亂,但當前最急迫的是現金不夠用。如果CES展後未能引入新資金,Faraday撐不過五月應該就會玩完。Faraday金主樂視對此表示全屬臆測,但拒絕進一步做評論。

    (本文內容由授權使用。圖片出處:法拉第未來)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

  • 騰訊入股Tesla,可望加速Model 3生產

    騰訊入股Tesla,可望加速Model 3生產

    騰訊於2017年3月29日宣布以17.8億美金買下Tesla 5%股權,此投資顯示騰訊對Elon Musk事業遠見之信心。騰訊資金的投入也有助於預定2017年底上市的Model 3。除此之外,Elon Musk在推特上回應關於太陽能瓦片的上市時間。

    外媒The Australian報導,汽車產業諮詢師Michael Dunne認為,騰訊旗下擁有中國最大的社群軟體微信(WeChat),如此有助於Tesla發展在中國生產製造的產線。Tesla過去曾和中國政府談論在中國建組裝廠一事,Elon Musk也表示若在中國建組裝廠不僅可以省下3分之1之成本,也可以省去進口關稅。

    根據中國的調查機構JL Warren Capital資料顯示,光是2016,中國向Tesla進口了11,839輛電動車,和2015相比成長了近5倍。騰訊與鴻海投資的新創汽車公司知行(FMC)預計在2020生廠自家的電動車,擁有Tesla股份也對FMC未來電動車布局有益。

    (首圖來源:Tesla)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

    FB行銷專家,教你從零開始的技巧

  • 中國新能源汽車補貼影響,比亞迪估Q1淨利將下滑

    中國新能源汽車補貼影響,比亞迪估Q1淨利將下滑

    比亞迪於28日晚間11點整公告表示,受新能源汽車補貼政策變動影響、產業短期會有所調整,2017年第1季集團新能源汽車業務也將承受一定壓力、預計新能源汽車銷量和盈利將有所下滑。此外,比亞迪也提到太陽能市場競爭依然激烈、產品價格壓力仍然較大。

    比亞迪表示,2016年底四部委發表的新能源汽車補貼新政將會對新能源汽車產業產生較大影響。由於2017年中國中央政府補貼額度比2016年降低20%、地方財政補貼不得超過中央財政單車補貼額的50%,一些規模較小的廠商及沒有實際競爭力的廠商可能會逐漸退出市場,整個市場的集中度將會進一步提升、龍頭企業將顯著受益,最終將促進新能源行業的持續健康發展。

    比亞迪預估2017年1-3月淨利將年減23.59-35.35%至5.5-6.5億元(人民幣)。

    比亞迪股份29日受上述消息衝擊而大幅走低。截至台北時間29日上午11時10分為止,比亞迪下跌2.81%至43.20港元;開盤迄今最低跌至42.85港元、創2月6日以來新低。

    股神巴菲特(Warren Buffett)掌管的波克夏海瑟威(Berkshire Hathaway)在2008年取得比亞迪10%股權。

    (本文內容由授權使用。圖片來源:比亞迪)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※超省錢租車方案

    ※教你寫出一流的銷售文案?

    網頁設計最專業,超強功能平台可客製化

  • 擴電動車版圖,鴻海投資中國鋰電池廠

    擴電動車版圖,鴻海投資中國鋰電池廠

    鴻海自2014開始將旗下事業版圖擴大至電動車領域,3月29日公告於深圳的子公司富泰華工業以44.7億新台幣買下中國寧德時代新能源1.19%之股權,共擁有7,666,525股。

    母公司為鋰電池製造商新能源科技(ATL),寧德時代(CATL)主要研發生產電池芯、電池管理系統和動力電池系統,產品應用於電動車及儲能領域。

    鴻海董事長郭台銘事業瞄準電動車市場,繼2015年旗下富士康同騰訊及和諧汽車,三方合資成立和諧富騰以生產智慧電動車之後,和諧富騰於2016又投資成立初創公司Future Mobility Corporation(FMC),瞄準高階智慧電動車。

    FMC於2017年1月宣布將斥資116億元人民幣,於南京建高端智能電動車廠,第一期工程預計2019年可以完成。關於此次寧德時代的投資,董事長郭台銘表示為長期投資。

    (首圖來源:寧德時代)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 積極拓電動車市場,Hyundai推EV車用平台

    積極拓電動車市場,Hyundai推EV車用平台

     

    特斯拉(Tesla)電動車成功引領話題,各大車廠跟紛紛仿效,搶攻此一市場。原本力推燃料電池車的韓國車廠–現代汽車(Hyundai Motor),眼看市場風向轉變,也宣布要研發該公司首款電動車專屬的車用平台(car platform)。

    路透社30日報導,車用平台意指外觀不同的汽車共享相通的設計、工程、生產流程,以及主要零件等,能夠壓低研發成本。現代汽車之前力推燃料電池車,如今轉攻電池車,突顯投資人施壓,要求該公司積極進軍新市場。

    現代汽車的電動車平台,電池將位於汽車底部,以便容納大容量電池,並讓車內空間最大化。現代-起亞環保車主管Lee Ki-sang說,電動車平台初期投資費用高,但是他們必須替未來做準備。分析師說現代別無選擇,必須追隨特斯拉、通用汽車、Daimler AG旗下的賓士(Mercedes-Benz),打造單獨的電動車平台,才能留在此一市場。

    Hi Investment & Securities分析師Ko Tae-bong表示,單獨平台初始時可能會造成虧損,但是現代若不研發長程電動車將落後對手,例如300、500、600公里車款。

    電動車大廠特斯拉(Tesla Inc.)要價35,000美元的平價車種「Model 3」預計2017年稍晚就能開賣,摩根士丹利(通稱大摩)認為,這款電動車的安全度會是一般車輛的10倍之多,發生死亡車禍的機率有望比其他車種低90%。

    MarketWatch、Business Insider等外電報導,大摩分析師Adam Jonas 23日發表研究報告指出,特斯拉為每台車安裝超級電腦後,車子安全性提升至其他車輛兩倍已經不夠看,他相信Model 3的安全度會是其他車輛的十倍之多,這會讓死亡車禍的發生機會降低90%。

    Jonas認為,缺少特斯拉駕車輔助科技的二手車價值將因而猛掉,未來甚至會被禁止上路。特斯拉蒐集資料的能力超群,還能將先進的安全輔助技術應用到電動車,還未推出類似科技的傳統車廠,競爭力堪虞。

    (本文內容由授權使用。圖片出處:Hyundai)  

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※超省錢租車方案

    ※別再煩惱如何寫文案,掌握八大原則!

    ※回頭車貨運收費標準

    ※教你寫出一流的銷售文案?

    FB行銷專家,教你從零開始的技巧

  • mysql大表在不停機的情況下增加字段該怎麼處理

    mysql大表在不停機的情況下增加字段該怎麼處理

    MySQL中給一張千萬甚至更大量級的表添加字段一直是比較頭疼的問題,遇到此情況通常該如果處理?本文通過常見的三種場景進行案例說明。

    1、 環境準備

    數據庫版本: 5.7.25-28(Percona 分支)

    服務器配置:  3台centos 7虛擬機,配置均為2CPU  2G內存

    數據庫架構: 1主2從的MHA架構(為了方便主從切換場景的演示,如開啟GTID,則兩節點即可),關於MHA搭建可參考此文 MySQL高可用之MHA集群部署

    準備測試表:  創建一張2kw記錄的表,快速創建的方法可以參考快速創建連續數

    本次對存儲過程稍作修改,多添加幾個字段,存儲過程如下:

    DELIMITER $$
    CREATE  PROCEDURE `sp_createNum`(cnt INT )
    BEGIN
        DECLARE i INT  DEFAULT 1;
        DROP TABLE  if exists  tb_add_columns;
        CREATE TABLE if not exists tb_add_columns(id int primary key,col1 int,col2 varchar(32));
        INSERT INTO tb_add_columns(id,col1,col2) SELECT i  as id ,i%7 as col1,md5(i) as col2;
        
        WHILE i < cnt DO
          BEGIN
            INSERT INTO tb_add_columns(id,col1,col2) SELECT id + i   as id ,( id + i) %7 as col1,md5( id + i) as col2  FROM tb_add_columns WHERE id <=cnt - i ;
            SET i = i*2;
          END;
        END WHILE;
    END$$
    DELIMITER ;

    調用存儲過程,完成測試表及測試數據的創建。

    mysql> call sp_createNum(20000000);

     2.  直接添加字段

    使用場景: 在系統不繁忙或者該表訪問不多的情況下,如符合ONLINE DDL的情況下,可以直接添加。

    模擬場景: 創建一個測試腳本,每10s訪問該表隨機一條記錄,然後給該表添加字段

    訪問腳本如下

    #!/bin/bash
    # gjc
    
    for i in  {1..1000000000}                    # 訪問次數1000000000,按需調整即可
    do
        id=$RANDOM                          #生成隨機數    
        mysql -uroot -p'123456' --socket=/data/mysql3306/tmp/mysql.sock  -e "select  a.*,now() from  testdb.tb_add_columns a where id = "$id     # 訪問數據
        sleep 10                            #  暫停10s
    done

    運行腳本

    sh  test.sh

     給表添加字段

    mysql> alter table  testdb.tb_add_columns add col3 int;

      此時,訪問正常。

     附ONLINE DDL的場景如下,建議DBA們必須弄清楚

    (圖片轉載於https://blog.csdn.net/finalkof1983/article/details/88355314)

     

     (圖片轉載於https://blog.csdn.net/finalkof1983/article/details/88355314)

    3.   使用工具在線添加

    雖然Online DDL添加字段時,表依舊可以讀寫,但是生產環境使用場景中對大表操作使用最多的還是使用工具pt-osc或gh-ost添加。

    本文主要介紹 pt-osc(pt-online-schema-change) 來添加字段,該命令是Percona Toolkit工具中的使用頻率最高的一種

    關於Percona Toolkit的安裝及主要使用可以參考  五分鐘學會Percona Toolkit 安裝及使用

    添加字段

    root@mha1 ~]# pt-online-schema-change --alter "ADD COLUMN  col4  int" h=localhost,P=3306,p=123456,u=root,D=testdb,t=tb_add_columns,S=/data/mysql3306/tmp/mysql.sock  --charset=utf8mb4 --execute

    主要過程如下:

    1> Cannot connect to A=utf8mb4,P=3306,S=/data/mysql3306/tmp/mysql.sock,h=192.168.28.132,p=...,u=root
    1> Cannot connect to A=utf8mb4,P=3306,S=/data/mysql3306/tmp/mysql.sock,h=192.168.28.131,p=...,u=root
    No slaves found.  See --recursion-method if host mha1 has slaves.  #  因為使用的是socket方式連接數據庫 且未配置root遠程連接賬號,所以會有此提示
    
    # A software update is available:
    Operation, tries, wait:
      analyze_table, 10, 1                                     
      copy_rows, 10, 0.25                                       
      create_triggers, 10, 1                      
      drop_triggers, 10, 1
      swap_tables, 10, 1
      update_foreign_keys, 10, 1
    Altering `testdb`.`tb_add_columns`...
    Creating new table...                                     #  創建中間表,表名為"_原表名_new"
    Created new table testdb._tb_add_columns_new OK.           
    Altering new table...                                     #  修改表,也就是在新表上添加字段,因新表無數據,因此很快加完
    Altered `testdb`.`_tb_add_columns_new` OK.                  
    2020-06-20T12:23:43 Creating triggers...                  #  創建觸發器,用於在原表拷貝到新表的過程中原表有數據的變動(新增、修改、刪除)時,也會自動同步至新表中
    2020-06-20T12:23:43 Created triggers OK.
    2020-06-20T12:23:43 Copying approximately 19920500 rows... # 拷貝數據,數據庫量是統計信息里的,不準確
    Copying `testdb`.`tb_add_columns`:  11% 03:50 remain       #  分批拷貝數據(根據表的size切分每批拷貝多少數據),拷貝過程中可以用show processlist看到對應的sql
    Copying `testdb`.`tb_add_columns`:  22% 03:22 remain
    Copying `testdb`.`tb_add_columns`:  32% 03:10 remain
    Copying `testdb`.`tb_add_columns`:  42% 02:45 remain
    Copying `testdb`.`tb_add_columns`:  51% 02:21 remain
    Copying `testdb`.`tb_add_columns`:  62% 01:48 remain
    Copying `testdb`.`tb_add_columns`:  72% 01:21 remain
    Copying `testdb`.`tb_add_columns`:  81% 00:53 remain
    Copying `testdb`.`tb_add_columns`:  91% 00:24 remain
    2020-06-20T12:28:40 Copied rows OK.                       # 拷貝數據完成
    2020-06-20T12:28:40 Analyzing new table...                # 優化新表
    2020-06-20T12:28:40 Swapping tables...                    # 交換表名,將原表改為"_原表名_old",然後把新表表名改為原表名
    2020-06-20T12:28:41 Swapped original and new tables OK.    
    2020-06-20T12:28:41 Dropping old table...                 #  刪除舊錶(也可以添加參數不刪除舊錶)
    2020-06-20T12:28:41 Dropped old table `testdb`.`_tb_add_columns_old` OK.
    2020-06-20T12:28:41 Dropping triggers...                  # 刪除觸發器
    2020-06-20T12:28:41 Dropped triggers OK.
    Successfully altered `testdb`.`tb_add_columns`.            # 完成

    修改過程中,讀寫均不受影響,大家可以寫個程序包含讀寫的

    注:  無論是直接添加字段還是用pt-osc添加字段,首先都得拿到該表的元數據鎖,然後才能添加(包括pt-osc在創建觸發器和最後交換表名時都涉及),因此,如果一張表是熱表,讀寫特別頻繁或者添加時被其他會話佔用,則無法添加。

    例如: 鎖住一條記錄

    用pt-osc添加字段,會發現一直卡在創建觸發器那一步

     此時查看對應的SQL正在等待獲取元數據鎖

    換成直接添加也一樣,例如

     當達到鎖等待后將會報錯放棄添加字段

    mysql> alter table  testdb.tb_add_columns add col5 int;
    ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

    對於此情況,需等待系統不繁忙情況下添加,或者使用後續的在從庫創建再進行主從切換

    4  先在從庫修改,再進行主從切換

    使用場景: 如果遇到上例中一張表數據量大且是熱表(讀寫特別頻繁),則可以考慮先在從庫添加,再進行主從切換,切換后再將其他幾個節點上添加字段。

    先在從庫添加(本文在備選節點添加)

    mysql> alter table  testdb.tb_add_columns add col5 int;
    Query OK, 0 rows affected (1 min 1.91 sec)
    Records: 0  Duplicates: 0  Warnings: 0

    進行主從切換

    使用MHA腳本進行在線切換

    masterha_master_switch  --conf=/etc/masterha/app1.conf --master_state=alive  --orig_master_is_new_slave --new_master_host=192.168.28.131  --new_master_port=3306

    切換完成后再對其他節點添加字段

    /* 原主庫上添加192.168.28.128  */
    mysql>  alter table  testdb.tb_add_columns add col5 int;
    Query OK, 0 rows affected (1 min 8.36 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    /* 另一個從庫上添加192.168.28.132  */
    mysql>  alter table  testdb.tb_add_columns add col5 int;
    Query OK, 0 rows affected (1 min 8.64 sec)
    Records: 0  Duplicates: 0  Warnings: 0

    這樣就完成了字段添加。

    5.  小結

    生產環境MySQL添加或修改字段主要通過如下三種方式進行,實際使用中還有很多注意事項,大家要多多總結。

    • 直接添加

    如果該表讀寫不頻繁,數據量較小(通常1G以內或百萬以內),直接添加即可(可以了解一下online ddl的知識)

    •  使用pt_osc添加

    如果表較大 但是讀寫不是太大,且想盡量不影響原表的讀寫,可以用percona tools進行添加,相當於新建一張添加了字段的新表,再降原表的數據複製到新表中,複製歷史數據期間的數據也會同步至新表,最後刪除原表,將新表重命名為原表表名,實現字段添加

    •  先在從庫添加 再進行主從切換

    如果一張表數據量大且是熱表(讀寫特別頻繁),則可以考慮先在從庫添加,再進行主從切換,切換后再將其他幾個節點上添加字段

     

     

     

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案