星期二, 6月 06, 2017

[HTML] img 標籤無法使用 ::after ::before

img 標籤無法使用::after,::before,不會有任何效果。

主要是因為img是void element,其定義跟範例如下:
Void elements can’t have any contents (since there’s no end tag, no content can be put between the start tag and the end tag).
Code Example

另外void element所以 img可以不用end tag ,<img>即可。

下面是不正確的void element。

<img>this is invalid img tag</img>

下次如果為了樣式要在img tag塞before/after pseudo element,還是乖乖用個span包住他吧。

Void elements
areabasebrcolembedhrimginputkeygenlinkmenuitemmetaparamsourcetrackwbr
Raw text elements
escapable raw text elements
Foreign elements
Elements from the MathML namespace and the SVG namespace.
Normal elements 
All other allowed html elements are normal elements.






星期一, 5月 08, 2017

OpenRTB 2.3 Reading Notes (CH.2)

OpenRTB(Version2.3) 第二章主要介紹基本原理

Chap 2. OpenRTB Basic

以流程面的話如下圖:
從Publishers來的request,到Buyers想要投遞廣告response。


Chap 2.1 Transport
  • 在交換資訊的過程主要是HTTP協定。特別是為了讓Bid Request能夠比使用HTTP GET更大的payload,HTTP POST則是必要使用的傳輸方式。
  • 除了空的Bid Response(推薦使用"No bid"作為稱呼)使用HTTP Code 204,其餘回傳HTTP Code 200。
  • 可以啟用HTTP Persistent Connections( Keep-Alive)優化網路連線。

Chap 2.2 Security
  • 由於上面的流程是Server-to-Server,SSL(Security Sockets Layer)並不是必要的傳輸規定。
  • 可透過其他方式保護連線,同時也可以降低上述流程的額外的處理。

星期四, 4月 13, 2017

[JavaScript] Strict Mode

[JavaScript] Strict Mode


ECMAScript 5的Strict Mode不是ECMAScript 的子集。
Strict Mode 執行上跟Non-Strict Mode下有明顯差異。
Strict Mode 跟Non-Strict Mode可並存。

Strict Mode 將JavaScript再執行一些陷阱語法直接丟明顯的錯誤。
Strict Mode 修正JavaScript Engine難以優化的錯誤。
Strict Mode 禁止了一些未來ECMAScript可能會使用的關鍵字。


開啟Strict Mode

"use strict";

  1. 放在語法前。
  2. 不要將”use strict”用在{}使用,他會失去效果。

{
"use strict";
}

  1. 可以在function scope開啟strict mode。
!function strict() {
  "use strict";
  function nested() {return "So am I!";}
  return "I am strict mode "+ nested();
}();
!function nonStrict() {return "I am non Strict";}();

Strict Mode執行上的不同

  1. 拼寫錯誤的變數(或沒有宣告就存取的變數)會拋出異常。
"use strict";
var nAme;
nEme = 17; // ReferenceError

  1. Silently Fail (程式碼執行不報錯也沒有效果的錯誤)會拋出異常。
"use strict";
var obj1 = {};
Object.defineProperty(obj1, "x", {value: 42, writeable: false}});
obj1.x = 9; //TypeError

var obj2 = {get x(){return 17;}};
obj2.x = 5; // TypeError

var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // TypeError

  1. 試圖刪除不可刪除之屬性會拋出異常
"use strict";
delete Object.prototype; // TypeError


  1. Gecko 34以前下方指令會丟出錯誤(ECMAScript6不存在)
"use strict";
var o = {p:1, p:2};

  1. 函數的參數要唯一
function sum(a, a, c) {
  "use strict";
  return a+b+c;
}

  1. 禁止八進位語法
var a = 0o10;
parseInt(a);

"use strict";
var sum = 015 + // SyntaxError
          197 +
          142;

  1. 禁止設置primitive值屬性
!function() {
"use strict";

false.true = "";              //TypeError
(14).sailing = "home";        //TypeError
"with".you = "far away";      //TypeError

}();


簡化變數(variable)的使用


  1. 禁止使用with
"use strict";
var x = 17;
with (obj) // SyntaxError
{
  x; // x mean obj.x or var x? it will make engine can not process optimization. 
}


  1. Strict Mode下的eval不在讓surrounding scope(包圍eval的scope),注入新變數。例如eval(‘var’)

function a () {
  eval('var x=10');
  console.log(x); //x will be create.
}


var x = 17;
var evalX = eval("'use strict'; var x = 42; x"); //this x !== var x=17
console.assert(x === 17);
console.assert(evalX === 42);

2.1 如果eval在Strict Mode下面執行,其代碼會被當作在Strict Mode下為執行。
function strict1(str) {
  'use strict';
  return eval(str); // str will be treated as strict mode code
}
function strict2(f, str) {
  'use strict';
  return f(str); // not eval(...): str is strict if and only
                 // if it invokes strict mode
}
function nonstrict(str) {
  return eval(str); // str is strict if and only 
                    // if it invokes strict mode
}

strict1("'Strict mode code!'");
strict1("'use strict'; 'Strict mode code!'");
strict2(eval, "'Non-strict code.'");
strict2(eval, "'use strict'; 'Strict mode code!'");
nonstrict("'Non-strict code.'");
nonstrict("'use strict'; 'Strict mode code!'");

  1. Strict Mode禁止刪除變數
'use strict';
var a={x:10};
delete a.x; // It can delete

var x;
delete x; // SyntaxError

eval('var y; delete y;'); // SyntaxError



簡化eval跟arguments

  1. 對eval跟arguments誤用的範例如下
"use strict";
eval = 17;
arguments++;
++eval;
var obj = { set p(arguments) { } };
var eval;
try { } catch (arguments) { }
function x(eval) { }
function arguments() { }
var y = function eval() { };
var f = new Function("arguments", "'use strict'; return 17;");

  1. Strict Mode 函數arguments的值,不會隨著參數變數被修改而跟著改變。
function f(a){
  "use strict";
  a = 42; //a 改變,但是函數的arguments仍是f(17);
  return [a, arguments[0]];
}
var pair = f(17);
console.assert(pair[0] === 42);
console.assert(pair[1] === 17);

  1. 不再支援arguments.callee (為了最佳化)
"use strict";
var f = function() { return arguments.callee; };
f(); // TypeError


安全的 JavaScript


  1. Strict Mode下回傳this將不再將整個this包裝(boxed)返回出去,而是undefined, 或是call, apply, bind的this。一般模式下會將this回傳出去,可能會包含許多額外資訊(ex window 物件),同時也有助效能提升。
  • 這也意味瀏覽器將不能透過Strict Mode下的function 回傳this來取得window物件捕捉額外資訊。
'use strict';
function fun() { return this; }
console.assert(fun() === undefined);
console.assert(fun.call(2) === 2);
console.assert(fun.apply(null) === null);
console.assert(fun.call(undefined) === undefined);
console.assert(fun.bind(true)() === true);

  1. Strict Mode下的arguments不再提供”walk” to JavaScript Stack的下面兩個方式 function.caller(誰呼叫我)跟function.arguments(呼叫我的函式的參數),因為這會導致不安全的存取。
function restricted()
{
  "use strict";
  restricted.caller;    // TypeError
  restricted.arguments; // TypeError
}
function privilegedInvoker()
{
  return restricted();
}
privilegedInvoker();

  1. Strict Mode下的arguments不再提供這個函數相關變數的存取方式,例如arguments.caller。這個在現在許多瀏覽器都已經不再存取的到。
 'use strict';
function fun(a, b) {
  'use strict';
  var v = 12;
  return arguments.caller; // throws a TypeError
}
fun(1, 2); // doesn't expose v (or a or b)

保留ECMAScript未來擴充的關鍵字

  1. 關鍵字範例如下
implements, interface, let, package, private, protected, public, static, yield

function package(protected){ // !!!
  "use strict";
  var implements; // !!!

  interface: // !!!
  while (true)
  {
    break interface; // !!!
  }

  function private() { } // !!!
}
function fun(static) { 'use strict'; } // !!!

  1. Strict Mode也禁止了Function Declaration 一些的宣告方式,這也是未來ECMAScript會制訂函式宣告式未來的一些規範。
 'use strict';
if (true)
  function f() { } // SyntaxError
  
for (var i = 0; i < 5; i++) 
  function f2() { } // SyntaxError


function baz() { // ok
  function eit() { } // ok
}


Reference: MDN Strict Mode 嚴格模式

星期四, 2月 09, 2017

Angular $rootScope and $scope Event System

Angular官方對的 $rootScope 的定義如下
Every application has a single root scope. All other scopes are descendant scopes of the root scope. Scopes provide separation between the model and the view, via a mechanism for watching the model for changes. They also provide event emission/broadcast and subscription facility.
 一個ng-app只會有一個 $rootScope,所有的 $scope 都是 $rootScope 的child scope。文件特別把angular的emission/broadcast機制放在定義,這也代表事件處理是 $rootScope 很重要的操作。

$scope.$emit up, $scope.$broadcast down


// firing an event upwards
$scope.$emit('myCustomEvent', 'Data to send');

// firing an event downwards
$scope.$broadcast('myCustomEvent', {
  someProp: 'Sending you an Object!' // send whatever you want
});

// listen for the event in the relevant $scope
$scope.$on('myCustomEvent', function (event, data) {
  console.log(data); // 'Data to send'
});


簡單說明這三個行為

  • $emit 往上(parent)觸發事件
  • $broadcast 往下(child)觸發事件
  • $on 當收到事件所執行的行為


但是$scope的互動並非都是parent-child關係,有可能是Sibling之間要觸發。這時候就會要先$emit parentScope在$broadcast,並不是很方便的寫法。


$scope.$parent.$broadcast('myevent', 'Some data');


$rootScope.($emit/$broadcast)


上面的這種sibling的事件觸發,則可以使用$rootScope代為處理,如下方案例。
簡單說明 $rootScope 的 $emit 跟 $broadcast 的差別。
  • $rootScope.$emit 因為$rootScope沒有父層,所以直接觸發 $rootScope 註冊的事件。
  • $rootScope.$broadcast 往下廣播事件。

<div ng-controller="ParentCtrl as parent" class="ng-scope">
  // ParentCtrl
  <div ng-controller="SiblingOneCtrl as sib1" class="ng-scope">
    // SiblingOneCtrl
  </div>
  <div ng-controller="SiblingTwoCtrl as sib2" class="ng-scope">
    // SiblingTwoCtrl
    <div ng-controller="ChildCtrl as child" class="ng-scope">
      // ChildCtrl
    </div>
  </div>
</div>



app.controller('SiblingOneCtrl',
  function SiblingOneCtrl ($rootScope) {

  $rootScope.$on('rootScope:emit', function (event, data) {
    console.log(data); // 'Emit!'
  });
  
  $scope.$on('rootScope:broadcast', function (event, data) {
    console.log(data); // 'Broadcast!'
  });
  
  $rootScope.$on('rootScope:broadcast', function (event, data) {
    console.log(data); // 'Broadcast!'
  });

});

app.controller('ChildCtrl',
  function ChildCtrl ($rootScope) {

  $rootScope.$emit('rootScope:emit', 'Emit!'); // $rootScope.$on
  $rootScope.$broadcast('rootScope:broadcast', 'Broadcast'); // $rootScope.$on && $scope.$on

});


Ref.1 AngularJS Offical Document: $rootScope
Ref.2 Understanding Angular’s $scope and $rootScope event system $emit, $broadcast and $on

星期三, 10月 05, 2016

React Component shouldComponentUpdate 實作


最近朋友遇到一個有趣的React問題,可能頁面上有個值,一秒鐘會有幾萬筆資料進來,但是如果要一直更新畫面,效果不好。

這邊我推薦使用shouldComponentUpdate 來阻擋這種一秒鐘幾十萬資料變動的畫面呈現議題。

範例程式碼如下
http://jsbin.com/lilubaj

1. ParentComponent每1ms變動一次數值給ChildComponent(this.state.count)。
2. ChildComponent會在畫面上呈現(this.props.count)。
3. shouldComponentUpdate 有個timer設置每1秒才會允許畫面更新一次。
4. componentWillReceiveProps 原本的資料還是每1ms都會更新(資料流是正確的)。



星期二, 7月 12, 2016

Redux middleware 筆記

使用redux middleware完成非同步呼叫

我們團隊在開始使用action->dispatch->reducer其實進入蠻快的
但是當進入到非同步的時候就卡關了
因為要在action creator要處理非同步,如果不使用middleware
我們可能會在action creator

export function addTodo(text) {
  setTimeout(function () { 
return { type: ADD_TODO, text }
  },3000)
}
但是reducer會跟你說錯,因為回來的東西並不是action而是一個function,reducer無法處理,這時候就需要middleware處理了。


我們大概可以把 middleware當作redux流程中的一部分。

action->dispatcher->customized async middleware-> reducer 產生新的state。

============async call sample===========

var Promise = require('bluebird');
var Superagent = require('superagent');

function asyncMiddleware(){
 return function store(store){ 
   return function next(next){ //next middleware
    return function actionHandle(action){ 
    if (typeof action.ASYNC_CALL !== 'undefined') {
     return next(action); 
     //如果action沒有關鍵字ASYNC_CALL,則直接走下一個middleware
    }
    var type = action.type;
    
    return new Promise(function promiseHandle(resolve, reject){
     //這邊我們使用bluebird的Promise來達成promise
     
     function responseCallback(responseError, response){
      //some code error handle or resolve promise

      next({
       type: type,
       response: response
      });
      
      resolve(response);
      
     }
     
     //do ajax call
     //這邊我們是使用superagent 來get/put/post/delete
     Superagent.get(target).query(params).set(header).end(responseCallback);
    });
   }
  }
 }
}

=========action creator=================
而我們的action creator就很簡單了
例如下面這個是非同步呼叫載入個人資料



export const LOADED_PROFILE = 'LOADED_PROFILE';
export function loadProfile(params) {
 return {
  'ASYNC_CALL': { //有此關鍵字 middleware會走 ajax call
   type: LOADED_PROFILE,
   method: 'get',
   target: '/profile/:pid',
   params: params
  }
 };
};

=========component/container===========

import { loadProfile } from 'actions/profile';

class Profile  extends Component {
 componentDidMount() {
  var params = {};//get/post的參數 
  this.props.loadProfile(params).then(function(result) {
   //do something
  });
 }
}
var mapDispatchToProps = { loadProfile };
export default connect(mapStateToProps, mapDispatchToProps)(Profile);


=========小結=====================

透過這種方式,團隊成員在使用redux流程都會很一致的
action->(middlewares)->reducer->store

不用知道middlewares的細節就可以完成開發
(不過當然我都有解釋給他們聽原理)



=========附註======================

我們是從redux-thunk的source code理解實作方法的
https://github.com/gaearon/redux-thunk/blob/master/src/index.js
只有短短10多行程式碼

redux middleware的說明官方文件跟有人從頭跑過一次redux middleware的中文說明
http://redux.js.org/docs/advanced/Middleware.html
http://huli.logdown.com/posts/294284-javascript-redux-middleware-details-tutorial



星期日, 7月 10, 2016

React-Redux 筆記

react-redux其實概念我整理如下

  • 有個中央控管的rootStore
  • 元件把自己需要的rootStore map回去變成自己的props
  • 元件可以發出action去變動rootStore 進而更新自己的畫面


=================Store層========================
rootStore管理整個React App的資料(我們先稱他為root)
ex:

{ root : 
 profile:{...profileData},
 friend: {...friendData},
 privacy: {...privacy}
}
=================Action定義層========================
action會定義我們的操作
ex:

const ADD_PROFILE_DATA = 'ADD_PROFILE_DATA';
addProfileData(data) {
 {
 type: ADD_PROFILE_DATA,// for reducer使用
 data:data //這個action會變動的資訊
 }
}

=================Reducer定義層========================
reducer負責處理 action來的狀態變化
所以跟rootStore類似,我們會拆幾個reducer來處理


rootReducer= combineReducers({
 profileReducer,
 friendReducer,
 privacyReducer
});

const profileReducer = function (state, action ) {

  switch(action.type) //action所定義的type
    case 'ADD_PROFILE_DATA'

    state.profile = action.data
    return state; //這兩個的意義 (state, action) => new state
  
    default: 
    return state;//沒定義的action不變動state
}

=================Component/Container(view)定義層=========
React-redux的元件跟react元件最大的不同就是有引入react-redux的connect()方法。



import { connect } from 'react-redux';
import {addProfileData} from 'action/profile';
class Profile extends Component { 
//react lifecycle method, render methor
}
mapStateToProps (state) {
  profile: state.profile 
  //我的Profile只需要profile的資料
  //就map rootStore的 profile變成自己的props
  //如果今天有其他的action變動到rootStore profile的資料
  //Profile也會跟著更新狀態
}

export default connect( 
  mapStateToProps, { addProfileData } ,{/*mergeProps*/},{/*option*/})( Profile );


要熟悉react-redux 對他提供的connect一定要熟悉
第一個連接的是這個component的mapStateToPros 這個function
第二個是這個component會發出的action,官方是稱他為 mapDispatchToProps
做了上述兩個動作,這個react component就在redux資料流當中了

this.props.profile就有相對應的資料
this.props.addProfileData 也可以dispatch透過reducer,更新rootStore的資料。

第三個參數 mergeProps 第四個為option
後兩個比較少用,避免混淆觀念,我這篇先跳過,有興趣可以參閱官方API
https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-apdispatchtoprops-mergeprops-options


=================後序========================
以上是最基本的redux在react的應用流程,
之後還有要跟大家說的,如果redux會使用到非同步呼叫或是其他功能需求(ex logger),
我們是使用redux middleware來完成。

星期二, 11月 05, 2013

[公告] 網誌搬家

各位好,最近把網誌搬到 - http://kvzhuang.logdown.com/ (其實已經搬了一段時間了)。

是個很不錯的部落格,歡迎大家多多瀏覽推薦阿。

之後會把網域也一併搬過去。

星期二, 8月 06, 2013

[COSCUP] 2013 COSCUP 參與心得

  這次參加COSCUP是我第一次參加。雖然我本身專注前端技術,但是其實本次的議程我並沒有只關注前端的議題,反而到處去看 Open Data,零時政府的議題。我才發現一個感覺是,我們並不是一群關上門來寫程式的人。我們十分關注時事,關切社會。


g0v.tw 高嘉良臥病仍不忘撰寫程式碼。(圖取自 inside.com.tw)

  這次的議題到處可以看到和時事相關的議題,拆政府,國防布。CLKao也有一句讓我印象十分深刻的話"政府應該停止使用網頁點擊率當作績效的KPI,而是資料的使用率做為績效的KPI"。

  文人使用文字改變社會,程式設計師使用程式碼改變社會。 Code 不再是只有社會的高級分子,立法委員能夠撰寫,你我都能夠參與改變社會,是我這次參加活動最大的感動。

零時政府網站
如何參與零時政府 g0v hackpad

  還有我在師大資工研究所老師,中央資工副教授鄭永斌老師也上台說 Lighten talk,表達他對希望資工所甄試有所變革的期望所下的行動。都是令人十分值得推廣的。



星期四, 7月 25, 2013

[人文] 驚喜合唱 101 Flash Mob Chorus in Taipei 101, Taiwan

  最近看到朋友分享了一個驚喜合唱 101 Flash Mob Chorus in Taipei 101, Taiwan。就很想要幫忙宣傳一下,真的會令人感動的台灣情!

  大家也可以幫忙轉貼出去啊! 台灣人就是那麼熱情有感情的民族。