ES6的核心语法与应用

一直以来都对ES6嗤之以鼻,本来灵活简单的Javascrit,非得为了提升B格,增加学习的成本,搞那么多鸡肋的语法。但是无奈俺们这些“老年jser”都被历史的车轮碾压了,现在如果不掌握ES6,估计很多代码都看不懂了。没有闲暇的午后时间来系统的学习ES6(其实还是有点抵触心理),但是为了跟上“年轻人”的步伐,随着用随着看随着学吧。力求以最简单的语言讲述。

模块

定义模块

语法为:

  • export function x () {}
  • export class
  • export default {}
// kittydar.js - 找到一幅图像中所有猫的位置
    export function detectCats(canvas, options) {
      var kittydar = new Kittydar(options);
      return kittydar.detectCats(canvas);
    }
    export class Kittydar {
      ... 处理图片的几种方法 ...
    }
    // 这个helper函数没有被export。
    function resizeCanvas() {
      ...
    }
    //默认的
    export default {
        xx: '111'
    }

引用模块

 import {detectCats} from "kittydar.js"; //引入某个方法
 import {detectCats, Kittydar} from "kittydar.js"; //引入并重命名
 import * as module from './module';//引入全部全部
 import helloWorld from './hello-world'; //引入默认
 function go() {
        var canvas = document.getElementById("catpix");
        var cats = detectCats(canvas);
        drawRectangles(canvas, cats);
    }

class用法

  • 基本语法 class A {}
  • 构造器 constructor {}
  • 继承 class A extends AParent {}
  • super()
  • 注意:类声明与函数声明不同,它不会被提升,所以先new 后class定义 会抛出异常
  • 静态变量:static compare(a, b) {}
//ES5
//使用Object.defineProperty实现可读属性make year
function Vehicle(make, year) {
  Object.defineProperty(this, 'make', {
    get: function() { return make; }
  });

  Object.defineProperty(this, 'year', {
    get: function() { return year; }
  });
}

Vehicle.prototype.toString = function() {
  return this.make + ' ' + this.year;
}

var vehicle = new Vehicle('Toyota Corolla', 2009);
console.log(vehicle.make); // Toyota Corolla
vehicle.make = 'Ford Mustang'; //静态属性
console.log(vehicle.toString()) // Toyota Corolla 2009
//ES6
class Vehicle {
  constructor(make, year) {
    this._make = make;
    this._year = year;
  }

  get make() {
    return this._make;
  }

  get year() {
    return this._year;
  }

  toString() {
    return 'xxx';
  }
}

var vehicle = new Vehicle('Toyota Corolla', 2009);

console.log(vehicle.make); // Toyota Corolla
vehicle.make = 'Ford Mustang';
console.log(vehicle.toString()) // Toyota Corolla 2009
//ES5的继承
function Motorcycle(make, year) {
  Vehicle.apply(this, [make, year]);
}

Motorcycle.prototype = Object.create(Vehicle.prototype, {
  toString: function() {
    return 'xxx';
  }
});

Motorcycle.prototype.constructor = Motorcycle;

//ES6
class Motorcycle extends Vehicle {
  constructor(make, year) {
    super(make, year);
  }

  toString() {
    return 'xxxx';
  }
}

箭头函数

  • 箭头函数的产生,主要由两个目的:更简洁的语法和与父作用域共享关键字this。
  • function和{}都消失了,所有的回调函数都只出现在了一行里。
  • 当只有一个参数时,()也消失了(rest参数是一个例外,如(…args) => …)。
  • 当{}消失后,return关键字也跟着消失了。单行的箭头函数会提供一个隐式的return(这样的函数在其他编程语言中常被成为lamda函数)。
  • 箭头函数没有它自己的this值,箭头函数内的this值继承自外围作用域。
  • 箭头函数与普通函数还有一个区别就是,它没有自己的arguments变量,但可通过rest参数获得。
function () { return 1; }
() => { return 1; }
() => 1

function (a) { return a * 2; }
(a) => { return a * 2; }
(a) => a * 2
a => a * 2

function (a, b) { return a * b; }
(a, b) => { return a * b; }
(a, b) => a * b

function () { return arguments[0]; }
(...args) => args[0]

() => {} // undefined
() => ({}) // {}
//在之前的js中setInterval会把this指向window,
//使用箭头函数this使用外层的作用域所以不用保存this指针
$('.current-time').each(function () {
  setInterval(() => $(this).text(Date.now()), 1000);
});
//箭头函数的arguments,通过rest函数可以获得
function log(msg) {
  const print = (...args) => console.log(args[0]);
  print(`LOG: ${msg}`);
} 
log('hello'); // LOG: hello

作用域

javascript本身是没有块级作用域的,ES6新增的let语法替代var实现了块级作用域。

//before
function func(arr) {
    for (var i = 0; i < arr.length; i++) {
        // i ...
    }
    // 这里也可以访问到i
}
//ES6
function func(arr) {
    for (let i = 0; i < arr.length; i++) {
        // i ...
    }
    // 这里访问不到i
}

React on ES6

详情参考 这篇文章

定义组件

// The ES5 way
var Photo = React.createClass({
  handleDoubleTap: function(e) { … },
  render: function() { … },
});
// The ES6+ way
class Photo extends React.Component {
  handleDoubleTap(e) { … }
  render() { … }
}

componentWillMount关键字

// The ES5 way
var EmbedModal = React.createClass({
  componentWillMount: function() { … },
});
// The ES6+ way
class EmbedModal extends React.Component {
  constructor(props) {
    super(props);
    //实现componentWillMount内容的地方像dom操作
  }
}

state和props初始化

// The ES5 way
var Video = React.createClass({
  getDefaultProps: function() {
    return {
      autoPlay: false,
      maxLoops: 10,
    };
  },
  getInitialState: function() {
    return {
      loopsRemaining: this.props.maxLoops,
    };
  },
  propTypes: {
    autoPlay: React.PropTypes.bool.isRequired,
    maxLoops: React.PropTypes.number.isRequired,
    posterFrameSrc: React.PropTypes.string.isRequired,
    videoSrc: React.PropTypes.string.isRequired,
  },
});

// The ES6+ way
// static 实现只读的props
// 全局state
class Video extends React.Component {
  static defaultProps = {
    autoPlay: false,
    maxLoops: 10,
  }
  static propTypes = {
    autoPlay: React.PropTypes.bool.isRequired,
    maxLoops: React.PropTypes.number.isRequired,
    posterFrameSrc: React.PropTypes.string.isRequired,
    videoSrc: React.PropTypes.string.isRequired,
  }
  state = {
    loopsRemaining: this.props.maxLoops,
  }
}

react中的事件


class PostInfo extends React.Component { constructor(props) { super(props); // Manually bind this method to the component instance... this.handleOptionsButtonClick = this.handleOptionsButtonClick.bind(this); } handleOptionsButtonClick(e) { // this应指向实例 this.setState({showOptionsModal: true}); } } //箭头函数this指向外层的组件 class PostInfo extends React.Component { handleOptionsButtonClick = (e) => { this.setState({showOptionsModal: true}); } }

实例

使用ES6改写的React组件程序

import React from 'react'
class Checkbox extends React.Component {
    constructor(props) {
        super(props);
        this.state = {isChecked: false};
        this.changeState = this.changeState.bind(this);
    }
    changeState () {
        this.setState({isChecked: !this.state.isChecked})
    }
    render() {
        return (<label>
            <input type="checkbox" checked={this.state.isChecked} onChange={this.changeState} />
            {this.state.isChecked ? this.props.labelOn : this.props.labelOff}
        </label>)
    }

}
export default Checkbox;

hadoop mapreduce set number of mappers

As a hadoop platform developer, my job is to maintain the hadoop platform , fix the potential bugs and develop the new feature to meet my company’s need.I don’t get involve in the specfic mr job development.But today,one of my college asked me if i know how to set the map number in mapreduce job, it make to search for a while.
We all know, we can set the reduce number by call setNumReduceTasks.However,when you use setNumMapTasks to set numbers of mappers,it does not work,because this configration is just a hint,the inputformat just ignore it and create the splits for the job.
So i just check the code in FileInputFormat.class, and found how to set number of mappers in mapreduce job.
1.For files which file size is larger then block size

ie. block size is 128MB,and file size is several GB, we can set the mapreduce.input.fileinputformat.split.minsize paramter in configuration class.
Configuraiton conf = getConf();
conf.set("mapreduce.input.fileinputformat.split.minsize",1374389534720);
this make split size to be 1GB.

2.For small files which file size is smaller then block size

ie the file size is several MB,we have to use the CombineTextInputFormat replace the FileInputFormat, and use mapreduce.input.fileinputformat.split.minsize with the inputformat together to set number of mappers.
job.setInputFormatClass(CombineSmallfileInputFormat.class);
Configuraiton conf = getConf();
conf.set("mapreduce.input.fileinputformat.split.minsize",1374389534720);
Then you can control the number of mappers in you mr programme.

Socket Read Timeout 引发的问题

线上一个流式向hadoop集群写入数据的系统需要保证写入exactly once,并且不能丢失数据。为了解决这一问题,我们采用了thrift+write ahead log来构建这一系统。在使用过程中一直效果很好,最近偶然间发现这个服务发送了重复的日志。
经过检查发现,原来是是thrift tsocket read timeout导致的问题。我们的系统逻辑是client端向该系统发送日志,如果抛出异常,会将日志落到本地,等待一段时间后从本地读出日志继续发送。检查日志后发现在client端抛出

java.net.SocketTimeoutException: Read timed out

这就解释了写入重复的问题,首先client通过thrift TSokcet向server发送日志,如果超时了,client端timeout,抛出异常,将该条日志写入本地,过一段时间重现发送。而server端由于处理繁忙,没有及时响应client,虽然client中断连接,但是Server接收到该日志,并进行了处理。过一段时间后client端重新发送就产生了重复日志。
通过脚本检查这一问题的严重性,大概一条最多只有一条,目前将client端的超时时间增大解决这一问题。

YARN-4493 ResourceManager moveQueue bug

When moving a running application to a different queue in resourceManger , the current implement don’t check if the app can run in the new queue before remove it from current queue. So if the destination queue is full, the app will throw exception, and don’t belong to any queue.
Here is the code

   private void executeMove(SchedulerApplication app, FSSchedulerApp attempt,
       FSLeafQueue oldQueue, FSLeafQueue newQueue) {
     boolean wasRunnable = oldQueue.removeApp(attempt);
     // if app was not runnable before, it may be runnable now
     boolean nowRunnable = maxRunningEnforcer.canAppBeRunnable(newQueue,
         attempt.getUser());
     if (wasRunnable && !nowRunnable) {
       throw new IllegalStateException("Should have already verified that app "
           + attempt.getApplicationId() + " would be runnable in new queue");

After that, the queue become orphane, can not schedule any resources. If you kill the app, the removeApp method in FSLeafQueue will throw IllealStateException of “Given app to remove app does not exist in queue …” exception.
So i think we should check if the destination queue can run the app before remove it from the current queue.
The patch is below:

   private void executeMove(SchedulerApplication app, FSSchedulerApp attempt,
       FSLeafQueue oldQueue, FSLeafQueue newQueue) {
-    boolean wasRunnable = oldQueue.removeApp(attempt);
     // if app was not runnable before, it may be runnable now
     boolean nowRunnable = maxRunningEnforcer.canAppBeRunnable(newQueue,
         attempt.getUser());
+    boolean wasRunnable = false;
+    if (nowRunnable) {
+        wasRunnable = oldQueue.removeApp(attempt);
+    }
     if (wasRunnable && !nowRunnable) {
       throw new IllegalStateException("Should have already verified that app "
           + attempt.getApplicationId() + " would be runnable in new queue");