Websocket example using dartlang and golang

If you have the following requirements :

1) transfer large data
2) client should update the ui only when new data updates are available in the server
3) don’t want the client to poll the server continuously
4) want to transfer data over nearly bare tcp connection, ie no http

then Websocket is the current best solution.

Websocket support is now available in latest common browsers and the support is built-in for javascript and dartlang. Non-web languages like golang also have
websocket packages.

I have posted the code for both server(Golang) and client(Dartlang) @ https://github.com/dennisfrancis/websocket-binarydata-example

Dart polymer datatable widget

I have created a polymer widget that draws a datatable from a data source url. The code is at https://github.com/dennisfrancis/polymer-dart-datatable-example

Here is the template of the polymer widget

<polymer-element name="dennis-datatable" attributes="dataSrc,jsonArgs,refreshInterval,method">
 
  <template>
  <link rel="stylesheet" href="dennis_datatable.css">

    <div>
      <button id="refresh_button" on-click="{{fetch_data}}">Refresh</button>
      <table class="bordered" id="datatable_table">
        <tr>
          <th template repeat="{{col in cols}}">
              {{col}}  
          </th>
        </tr>
        <tr template repeat="{{row in rows}}">

            <td template repeat="{{col in cols}}">
              {{row[col]}}  
            </td>
        </tr>
      </table>
    </div>
  </template>
  <script type="application/dart" src="dennis_datatable.dart"></script>
</polymer-element>

And here is the dart code of the widget that also prints the rendering latency to the Dartium console.

import 'package:polymer/polymer.dart';
import 'dart:async';
import 'dart:html';
import 'dart:convert';

/**
 * A Polymer datatable element.
 */
@CustomTag('dennis-datatable')
class DataTable extends PolymerElement {
  @published String dataSrc;
  @published String jsonArgs = "{}";  // Sorting can be done on server side by passing something like sortcol:"colname"
  @published int refreshInterval = 0;
  @published String method = "GET";
  
  @observable int numrows = 0;
  @observable int numcols = 0;
  @observable List<String> cols;
  @observable List<Map<String,dynamic>> rows;
  
  ButtonElement refreshButton;
  bool doing_refresh = false;
  
  Timer fetch_timer;
  
  String _json_response = "";
  
  MutationObserver observer;
  
  DateTime _start_render;
  DateTime _stop_render;

 
  DataTable.created() : super.created() {
    
    observer = new MutationObserver(_onMutation);
    observer.observe(getShadowRoot('dennis-datatable').querySelector('#datatable_table'), childList: true, subtree: true);

    refreshButton = this.shadowRoot.querySelector("#refresh_button");
    
    fetch_data();
    
    if (refreshInterval != 0) {
      fetch_timer = new Timer.periodic(new Duration(seconds : refreshInterval), fetch_data);
    }
  }
  
  void _onMutation(List<MutationRecord> mutations, MutationObserver observer) {
    print('${mutations.length} mutations occurred, the first to ${mutations[0].target}');
    _prn_stat();
  }
  
  void fetch_data([Timer _]) {

    if (doing_refresh) { return; }
    
    refreshButton.disabled = true;
    
    doing_refresh = true;

 
    if (dataSrc.isEmpty) { return; }

    HttpRequest request = new HttpRequest(); // create a new XHR
    
    // add an event handler that is called when the request finishes
    request.onReadyStateChange.listen((_) {
      if (request.readyState == HttpRequest.DONE &&
          (request.status == 200 || request.status == 0)) {
        // data saved OK.
        //print(request.responseText); // output the response from the server
        if (_json_response != request.responseText) {  // Avoid json parsing and rendering if same data
          update_data(request.responseText);
          _json_response = request.responseText;
        } else {
          print("No new data");
        }
        
      }
      doing_refresh = false;
      refreshButton.disabled = false;
    });

    // POST the data to the server
    request.open(method, dataSrc);

    if(method == "POST") {
      request.send(jsonArgs); // perform the async POST
    } else {
      request.send();
    }
    
  }
    
  void update_data(String jsonString) {
    
    Map data = JSON.decode(jsonString);
    
    numrows = data["numrows"];
    numcols = data["numcols"];
    cols    = data["cols"];
    rows    = data["rows"];
    
    _start_render = new DateTime.now();
    
  }
  
  void _prn_stat() {

    if (_start_render == null) { return; }
    
    _stop_render = new DateTime.now();
    int diff = _stop_render.millisecondsSinceEpoch - _start_render.millisecondsSinceEpoch;
    
    print("render time = $diff ms");
    
  }
  
}

The sad part about this widget is that the rendering time is about 20 times worse than what it would take a raw dart program to generate a table with the same data.
See my previous post about rendering latency without using polymer widgets.

I decided to move the table rendering logic from templates to a dart function, until polymer template rendering speed improves. I created a new git branch called min_templates for the same project at github.

Now the rendering latency is competitive to that of the non-polymer dart table benchmark

 

Table rendering performance with dart, dart2js and handwritten js

The data for creating the table is a matrix of 4000 rows x 10 cols of random strings.

I tested the table rendering performance for the following scenarios with the same data

  1. Dart code generating the table and run in Dartium (Chromium browser with Dart VM built-in) with checked mode disabled
  2. Ran dart2js on the same dart code and ran it on Chromium
  3. Hand-written JS program with no table libraries
  4. Hand-written JS program with Google table library.
I have posted the code for all these tests at github. [https://github.com/dennisfrancis/table-rendering-benchmark]

Test pseudocode


fetch_test_data()
run_table_render()
run_table_render()
start_time = now()
loop 20 times {
cleanup_table_html()
run_table_render()
}
stop_time = now()
avg_time = (stop_time - start_time)/20
report avg_time in milliseconds

Software versions
Dart Editor version 1.0.0_r30798 (STABLE)
Dart SDK version 1.0.0.10_r30798

Dartium Version 31.0.1650.39 (1593)
Chromium Version 27.0.1453.93 Built from source for Fedora release 19 (Schrödinger’s Cat) (200836)

Results

Table rendering performance (Smaller is better)