вторник, 30 января 2018 г.

Разница между nextTick и setImmediate

Функция process.nextTick() помещается в начало очереди следующего цикла event loop и должна называться process.sendThisToTheStartOfTheQueue().

А setImmediate() помещается в конец очереди следующего цикла event loop и должна называться sendThisToTheEndOfTheQueue().

четверг, 23 ноября 2017 г.

Redux Очень короткая шпаргалка

import {createStore, combineReducers, applyMiddleware} from 'redux';

// Counter

var counterActionType = {
    'UP': 'UP'
};

function couterActionCreator (value) {
    return {
  type: counterActionType.UP,
        value: value
    };
}

function counterReducer (state, action) {
    if (state === undefined) {state = {counter: 0};}
    switch (action.type) {
        case counterActionType.UP: return Object.assign({}, state, {counter: state.counter + action.value});
        default: return state;
     }
}

// Time

var timeActionType = {
    'UPDATE': 'UPDATE'
};

function timeActionCreator (value) {
    return {
        type: timeActionType.UPDATE,
        value: value
    };
}

function timeReducer (state, action) {
    if (state === undefined) {state = {time: new Date()};}
    switch (action.type) {
        case timeActionType.UPDATE: return Object.assign({}, state, {time: new Date(state.time.getTime() + action.value)});
        default: return state;
    }
}

var rootReducer = combineReducers({
    counterObject: counterReducer,
    timeObject: timeReducer
});

var initialState = {
    counterObject: {counter: 2},
    timeObject: {time: new Date()}
};

var store = createStore(rootReducer, initialState, applyMiddleware(/* createLogger(), thunkMiddleware */));

var unsubscribeStore = store.subscribe(function storeChangeListener () {
    console.log(store.getState());
});

console.log(store.getState().counterObject.counter);

store.dispatch(couterActionCreator(1));

console.log(store.getState().counterObject.counter);

unsubscribeStore();

store.dispatch(couterActionCreator(1));

console.log(store.getState().counterObject.counter);

store.dispatch(timeActionCreator(1000000));

console.log(store.getState().timeObject.time);

среда, 22 ноября 2017 г.

React Очень короткая шпаргалка



import React, {Component} from 'react';
import ReactDOM from 'react-dom';

class Time extends Component {
  // Actions
  handleCounterUp () {
    this.setState(Object.assign({}, this.state, {counter: this.state.counter + 1}));
  }
  handleInputChange (event) {
    this.setState(Object.assign({}, this.state, {value: event.target.value.toUpperCase()}));
  }
  handleSubmitForm (event) {
    event.preventDefault();
    alert('Value: ' + this.state.value);
  }
  // First render (only once)
  constructor (props) {
    super(props);
    this.state = {
      time: null,
      counter: 0,
      value: ''
    };
    this.handleCounterUp = this.handleCounterUp.bind(this);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleSubmitForm = this.handleSubmitForm.bind(this);
  }
  // setState OK
  componentWillMount () {
    this.setState(Object.assign({}, this.state, {time: new Date()}));
  }
  render () {
    return (
      <div>
        {/* Это комментарий */}
        <p>
          <span>пробелы</span>{' '}
          <span>между тэгами</span>{' '}
          <span>на разных строках</span>
        </p>
        <ul>
          {
            [1, 2, 3].map(
              function (value, index) {
                return <li key={index}>{value}</li>;
              }
            )
          }
        </ul>
        <div ref="message">My message</div>
        <div>{this.state.time.toString()}</div>
        <div>{this.props.time.toString()}</div>
        <div>{this.state.counter}</div>
        <div onClick={this.handleCounterUp}>Counter up</div>
        <form onSubmit={this.handleSubmitForm}>
          <input type="text" value={this.state.value} onChange={this.handleInputChange} />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
  componentDidMount () {
    var self = this;
    this.timeoutId = setTimeout(function () {
      self.setState(Object.assign({}, self.state, {time: new Date()}));
    }, 1000);
    // Actions after we updated DOM
    // Here we can use jQuery to manipulate the DOM
    // $('input-id).val('');
    console.log(this.refs.message.innerText);
  }
  // Unmount in the end
  componentWillUnmount () {
    clearTimout(this.timeoutId);
  }
  // Next Props change - setState OK
  componentWillReceiveProps (nextProps) {
    this.setState(Object.assign({}, this.state, {time: nextProps.time}));
  }
  // Props change or only Next State change
  shouldComponentUpdate (nextProps, nextState) {
    return this.state.time.getTime() !== nextProps.time.getTime();
  }
  // No setState
  componentWillUpdate (nextProps, nextState) {
    // Actions before we updated DOM
  }
  // Render and then
  componentDidUpdate (prevProps, prevState) {
    // Actions after we updated DOM
    // Here we can use jQuery to manipulate the DOM
    // $(this._ref.input).val(');
    console.log(this.refs.message.innerText);
  }
}

ReactDOM.render(<Time time={new Date(new Date().getTime() + 100000000)} />, document.getElementById('root'));

пятница, 27 октября 2017 г.

TypeScript Краткая шпаргалка

// Объявление переменных

var a: number = 1;
let b: number = 2;
const c: number = 3;

// Типы переменных

let an: any = 0;
let unusable: void = undefined; // Может иметь только значение undefined или null
let undef: undefined = undefined;
let nul: null = null;
let bool: boolean = true;
let num: number = 1;
let str: string = 'text';
let arr1: number[] = [1, 2, 3];
let arr2: Array<number> = [1, 2, 3];
let arr3: ReadonlyArray<number> = [1, 2, 3];
let tuple: [number, string] = [1, 'text'];
let matrix: number[][] = [[1, 2], [3, 4]];
let obj: {a?: number} =  {a: 1};
let union: undefined | null | string | number = 'text';

enum Color {Red = 1, Green = 2, Blue = 3}
let enu: Color = Color.Red;

function func (a?: number, b?: string): void {
    return;
}

function error (message: string = 'text'): never {
    throw new Error(message);
}

let [first, second, ...rest] = [1, 2, 3, 4];

let {one, two}: {one: string, two: number} = {
    one: 'text',
    two: 1
};

// Приведение типов переменных

let someValue: any = 'this is a string';
let strLength1: number = (someValue as string).length;
let strLength2: number = (<string>someValue).length;

// Объявление функций

function func1 (a?: number, b?: string): void {
    return;
}

const func2 = function  (a?: number, b?: string): void {
    return;
};

const func3 = (a?: number, b?: string): void => {
    return;
};

const func4: (x: number, y: number) => number = function (x: number, y: number): number {
    return x + y;
};

function func5 (): Fish | Bird {
    // ...
}

// Перегрузка функции

function pickCard(x: {suit: string; card: number; }[]): number;
function pickCard(x: number): {suit: string; card: number; };
function pickCard(x): any {
    if (typeof x == "object") {
        return Math.floor(Math.random() * x.length);
    } else if (typeof x == "number") {
        return {suit: suits[Math.floor(x / 13)], card: x % 13 };
    }
}

// Объявление классов

abstract class Animal {

    abstract makeSound(): void;

    move(): void {
        console.log('roaming the earth...');
    }

}

class A extends B implements BInterface {

    readonly numberOfLegs: number = 8;

    private currentTime: Date;

    protected name: string;

    public h: number;

    public constructor (h: number, public m: number) {
        super(m, h);
    }

    public setTime (d: Date) {
        this.currentTime = d;
    }

    private count = (a: number): void => {
        super.count(a);
        console.log(a);
    }

    private static say (b: string): string {
        return b;
    }

    private _fullName: string;

    get fullName(): string {
        return this._fullName;
    }

    set fullName (newName: string) {
        this._fullName = newName;
    }

}

let a: A = new A(10, 20);

class Point {
    x: number;
    y: number;
}

interface Point3d extends Point {
    z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};

// Объявление интерфейсов

interface IOne {
     str?: string;
     [index: number]: string;
     func (a: number): number;
}

interface ITwo extends IOne {
    readonly obj: {b: number};
    [propName: string]: any;
    new (hour: number, minute: number);
}

// Объявление дженериков

function identity<T> (arg: T): T {
    return arg;
}

let output = identity<string>('myString');

let myIdentity: <T>(arg: T) => T = identity;

interface GenericIdentityFn {
    <T>(arg: T): T;
}

let myIdentity: GenericIdentityFn = identity;

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
    return x + y;
};

function create<T> (c: {new(): T;}): T {
    return new c();
}

interface NotEmpty<T> {
    data: T;
}
let x: NotEmpty<number>;
let y: NotEmpty<string>;

function extend<T, U> (first: T, second: U): T & U {
    let result = <T & U>{};
    for (let id in first) {
        (<any>result)[id] = (<any>first)[id];
    }
    for (let id in second) {
        if (!result.hasOwnProperty(id)) {
            (<any>result)[id] = (<any>second)[id];
        }
    }
    return result;
}

function pluck<T, K extends keyof T> (o: T, names: K[]): T[K][] {
    return names.map(n => o[n]);
}

// Объявление типов

type Name = string;

type NameResolver = () => string;

type NameOrResolver = Name | NameResolver;

function getName(n: NameOrResolver): Name {
    if (typeof n === 'string') {
        return n;
    } else {
        return n();
    }
}

type Easing = "ease-in" | "ease-out" | "ease-in-out";

type Shape = Square | Rectangle | Circle;

type Container<T> = {
    value: T
};

type Tree<T> = {
    value: T;
    left: Tree<T>;
    right: Tree<T>;
}

type LinkedList<T> = T & {next: LinkedList<T>};

type Proxy<T> = {
    get(): T;
    set(value: T): void;
}

type Proxify<T> = {
    [P in keyof T]: Proxy<T[P]>;
}

function proxify<T>(o: T): Proxify<T> {
   // ... wrap proxies ...
}

let proxyProps = proxify(props);

let personProps: keyof Person; // 'name' | 'age'

// Декларирование типов

type Alias = {num: number}

interface Interface {
    num: number;
}

declare function aliased (arg: Alias): Alias;

declare function interfaced (arg: Interface): Interface;

declare function require (moduleName: string): any;

// Пространство имен

namespace Validation {

    export class ZipCodeValidator implements StringValidator {
        isAcceptable (s: string) {
            return s.length === 5 ;
        }
    }

}

namespace Shapes {
    export namespace Polygons {
        export class Triangle { }
        export class Square { }
    }
}

declare namespace D3 {

    export interface Selectors {
        select: {
            (selector: string): Selection;
            (element: EventTarget): Selection;
        };
    }

    export interface Event {
        x: number;
        y: number;
    }

    export interface Base extends Selectors {
        event: Event;
    }

}

declare var d3: D3.Base;

// Декораторы

function f () {
    console.log("f(): evaluated");
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("f(): called");
    }
}

function g () {
    console.log("g(): evaluated");
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("g(): called");
    }
}

class C {
    @f()
    @g()
    method() {}
}

// f(): evaluated
// g(): evaluated
// g(): called
// f(): called

function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) {
    return class extends constructor {
        newProperty = "new property";
        hello = "override";
    }
}

@classDecorator
class Greeter {
    property = "property";
    hello: string;
    constructor(m: string) {
        this.hello = m;
    }
}

console.log(new Greeter("world"));

class Point {
    private _x: number;
    private _y: number;
    constructor(x: number, y: number) {
        this._x = x;
        this._y = y;
    }

    @configurable(false)
    get x() { return this._x; }

    @configurable(false)
    get y() { return this._y; }
}

// Импорт

import "./my-module.js";

export * from "./ZipCodeValidator";
import * as validator from "./ZipCodeValidator";

import ZipCodeValidator from "./ZipCodeValidator";
import {ZipCodeValidator} from "./ZipCodeValidator";
import {ZipCodeValidator as ZCV} from "./ZipCodeValidator";

// Экспорт

declare let $: JQuery;

export default $;

export default "123";

export default function (s: string) {
    return s.length === 5;
}

export default class ZipCodeValidator {
    isAcceptable (s: string) {
        return s.length === 5;
    }
}

export ZipCodeValidator;

export interface StringValidator {
    isAcceptable (s: string): boolean;
}

export class LettersOnlyValidator implements StringValidator {
    isAcceptable (s: string) {
        return lettersRegexp.test(s);
    }
}

среда, 25 октября 2017 г.

React, Readux, React-Redux, Redux-Thunk краткая шпаргалка

import React from "react";
import {render} from "react-dom";
import {createStore, combineReducers, applyMiddleware} from "redux";
import thunk from "redux-thunk";
import {Provider, connect} from "react-redux";

const couterUpActionCreator = value => {
  return {
    type: "COUNTER_UP",
    value: value
  };
};

const counterDownActionCreator = value => {
  return {
    type: "COUNTER_DOWN",
    value: value
  };
};

const counterDownAsyncActionCreator = value => {
  return dispatch => {
    setTimeout(() => {
      dispatch(counterDownActionCreator(value));
    }, 1000);
  };
};

const countReducer = (state = 0, action) => {
  switch (action.type) {
    case "COUNTER_UP": return state + action.value;
    case "COUNTER_DOWN": return state - action.value;
    default: return state;
  }
};

const counterReducer = combineReducers({
  count: countReducer
});

const rootReducer = combineReducers({
  counter: counterReducer
});

const initialState = {
  counter: {
    count: 0
  }
};

const store = createStore(rootReducer, initialState, applyMiddleware(thunk));

store.subscribe(() => {
  console.log(store.getState());
});

class Counter extends React.Component {
  styles = {
    fontFamily: "sans-serif",
    textAlign: "center"
  }
  constructor (props) {
    super(props);
  }
  componentWillMount () {
    console.log("Component Will Mount");
  }
  render () {
    console.log('Render');
    return (
      <div style={this.styles}>
        <div>{this.props.propsFromApp}</div>
        <br />
        <div onClick={this.handleUpClick}>^</div>
        <div>{this.props.count}</div>
        <div onClick={this.handleDownClick}>v</div>
      </div>
    );
  }
  componentDidMount () {
    console.log("Component Did Mount");
  }
  componentWillReceiveProps (nextProps) {
    console.log("Component Will Recieve Props");
  }
  shouldComponentUpdate (nextProps, nextState) {
    console.log("Should Component Update");
    if (this.props.propsFromApp !== nextProps) {
      return true;
    } else {
      return false;
    }
  }
  componentWillUpdate (nextProps, nextState) {
    console.log("Component Will Update");
  }
  componentDidUpdate (prevProps, prevState) {
    console.log("Component Did Update");
  }
  componentWillUnmount () {
    console.log("Component Wiil Unmount");
  }
  handleUpClick = () => {
    this.props.counterUp();
  }
  handleDownClick = () => {
    this.props.counterDown();
  }
}

const mapStateToProps = state => {
  return {
    count: state.counter.count
  };
};

const mapDispatchToProps = dispatch => {
  return {
    counterUp: () => {
      dispatch(couterUpActionCreator(1));
    },
    counterDown: () => {
      dispatch(counterDownAsyncActionCreator(1));
    }
  };
};

const ConnectedCounter = connect(mapStateToProps, mapDispatchToProps)(Counter);

class App extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      propsFromApp: 0
    };
  }
  render () {
    return (
      <div>
        <div onClick={this.handleClick}>UPDATE STATE AND PROPS</div>
        <ConnectedCounter propsFromApp={this.state.propsFromApp} />
      </div>
    );
  }
  handleClick = () => {
    this.setState(
      Object.assign(
        {},
        this.state,
        {
          propsFromApp: this.state.propsFromApp + 1
        }
      )
    );
  }
}

render(<Provider store={store}><App /></Provider>, document.getElementById("root"));

понедельник, 18 сентября 2017 г.

Node.js Cluster - особенности работы

const cluster = require('cluster')
        , http = require('http')
        , os = require('os');

const cpus = os.cpus().length;

// 3 Уровня создание кластера воркеров

// 1 уровень - уровень прослушивания всех событий для всех воркеров

cluster.on('message', function (worker, message, handle) {
    console.log('All messages: ' + worker.id + ' | ' + message);
});

cluster.on('fork', function (worker) {
    console.log('Worker ' + worker.id + ' forked.');
});

if (cluster.isMaster) {
    // 2 уровень - уровень создания воркеров и уровень прослушивания событий для каждого конкретного воркера
    for (let i = 0; i < cpus; i++) {
        let worker = cluster.fork(); // Создание воркера
        // Навешивание событий на конкретный созданный воркер
        worker.on('listening', (address) => {
            console.log(JSON.stringify(address));
        });
        worker.on('message', function (message) { // Получение сообщения из мастер-процесса кластера
            console.log(message + ' master ' + process.pid);
            worker.send('shutdown'); // Посылка сообщения из воркера в мастер-процесс кластера
            worker.kill(); // Уничтожение текущего активного воркера
        });
    }
    cluster.on('exit', function (worker, code, signal) {
        console.log('Worker ' + worker.id + ' killed.');
    });
} else if (cluster.isWorker) {
    // 3 уровень - уровень кода воркера и посылки сообщений из мастер-процесса кластера текущему активному воркеру
    // Код воркера
    http.createServer(function (request, response) {
        response.writeHead(200, 'OK');
        response.end('HI ' + process.pid);
        process.send('Done: ' + process.pid); // Посылка сообщения из мастер-процесса кластера текущему активному воркеру
    }).listen(8000, '127.0.0.1', function () {
        console.log('Server started ' + process.pid);
    });
    // Получение сообщения из текущего активного воркера мастер-процессом кластера
    process.on('message', function (message) {
        console.log('Message from worker: ' + message);
    });
}

среда, 13 сентября 2017 г.

Node.js UDP / Dgram Server and Client

const dgram  = require('dgram');

// Server

const server = dgram.createSocket('udp4');

server.on('listening', function () {
    console.log('Server listening: ' + JSON.stringify(server.address()));
});

server.on('message', function (message, rinfo) {
    console.log('Server got message: "' + message + '" from: ' + rinfo.address + ':' + rinfo.port);
    server.send(message, 0, rinfo.size, rinfo.port, rinfo.address, function (error) {
        if (error) {throw error;}
        server.close();
    });
});

server.on('close', function () {
    console.log('Server closed');
});

server.on('error', function (error) {
    console.log('Server error: ' + error.stack);
    server.close();
});

server.bind(8080, '127.0.0.1', function () {
    console.log('Datagram server started at 127.0.0.1:8080');
});

// Client

const client = dgram.createSocket('udp4');

client.on('message', function (message, rinfo) {
    console.log('Client got message: "' + message + '" from: ' + rinfo.address + ':' + rinfo.port);
    client.close();
});

client.on('close', function () {
    console.log('Client closed');
});

client.on('error', function (error) {
    console.log('Client error: ' + error.stack);
    client.close();
});

client.send([Buffer.from('Some bytes.'), Buffer.from(' And another bytes.')], 8080, '127.0.0.1', function (error) {
    if (error) {throw error;}
});