Git Product home page Git Product logo

hstardoc's Introduction

HstarDoc

markdown docs. Save my markdown blogs.

Table of Contents

The End

hstardoc's People

Contributors

hstarorg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hstardoc's Issues

Yeoman 常用的generators

Yeoman Generators 仓库:http://yeoman.io/generators/

React

1、https://github.com/newtriks/generator-react-webpack
Using React with Webpack via Babel
2、https://github.com/kriasoft/react-starter-kit
React.js projects based on React Starter Kit (ES6+, Babel, React.js, Express, Webpack, BrowserSync)
3、https://github.com/stylesuxx/generator-react-webpack-redux
React Webpack Generator including Redux support

Angular

4、https://github.com/angular-fullstack/generator-angular-fullstack
Creating MEAN stackapps, using MongoDB, Express, AngularJS, and Node
5、https://github.com/swiip/generator-gulp-angular
AngularJS with Gulp
6、https://github.com/yeoman/generator-angular
AngularJS

Angular2

7、https://github.com/mcfly-io/generator-mcfly-ng2
Scaffolding an app using angular2 and webpack
8、https://github.com/swirlycheetah/generator-angular2
Angular2 Generator

常用排序算法汇总

排序算法

快速排序

/**
 * 快速排序
 * @param arr
 */
function quickSort(arr) {
  var middle = arr[Math.floor(arr.length / 2)];
  var beforeArr = [];
  var afterArr = [];
  var middleArr = [];
  // 分
  for (var i = 0, len = arr.length; i < len; i++) {
    if (arr[i] === middle) {
      middleArr.push(arr[i]);
    } else if (arr[i] < middle) {
      beforeArr.push(arr[i]);
    } else {
      afterArr.push(arr[i]);
    }
  }
  // 分 End
  if (beforeArr.length > 1) {
    beforeArr = quickSort(beforeArr);
  }
  if (afterArr.length > 1) {
    afterArr = quickSort(afterArr);
  }
  return [...beforeArr, ...middleArr, ...afterArr];
}

冒泡排序

/**
 * 冒泡排序
 * @param arr
 */
function bubbleSort(arr) {
  const resultArr = arr.slice(0);
  for (var i = 0, len = resultArr.length; i < len; i++) {
    for (var j = 0; j < len - i - 1; j++) {
      if (resultArr[j] > resultArr[j + 1]) {
        // 交换
        var temp = resultArr[j];
        resultArr[j] = resultArr[j + 1];
        resultArr[j + 1] = temp;
      }
    }
  }
  return resultArr;
}

选择排序

/**
 * 选择排序
 * @param arr
 */
function selectSort(arr) {
  var resultArr = arr.slice(0);
  for (var i = 0, len = resultArr.length; i < len; i++) {
    var minIdx = i;
    for (var j = i + 1; j < len; j++) {
      if (resultArr[j] < resultArr[minIdx]) {
        minIdx = j;
      }
    }
    // 交换
    var temp = resultArr[i];
    resultArr[i] = resultArr[minIdx];
    resultArr[minIdx] = temp;
    // 装逼写法,实际性能差
    // [resultArr[i], resultArr[minIdx]] = [resultArr[minIdx], resultArr[i]];
  }
  return resultArr;
}

插入排序

/**
 * 插入排序
 * @param arr
 */
function insertionSort(arr) {
  var resultArr = arr.slice(0);
  // 想想打扑克的时候,没摸一张牌,都根据大小插入到手中已有的牌中
  for (var i = 1, len = resultArr.length; i < len; i++) {
    // 摸牌
    var card = resultArr[i];
    var j = i - 1;
    // 从右往左,看手里的牌,如果比刚摸的牌大,就腾位置
    while (j >= 0 && resultArr[j] > card) {
      resultArr[j + 1] = resultArr[j];
      j--;
    }
    // 放牌
    resultArr[j + 1] = card;
  }
  return resultArr;
}

归并排序

/**
 * 归并排序
 * @param arr
 */
function mergeSort(arr) {
  var splitIdx = Math.floor(arr.length / 2);
  var beforeArr = arr.slice(0, splitIdx);
  var afterArr = arr.slice(splitIdx);
  if (beforeArr.length > 1) {
    beforeArr = mergeSort(beforeArr);
  }
  if (afterArr.length > 1) {
    afterArr = mergeSort(afterArr);
  }
  var resultArr = [];
  var beforeIdx = 0,
    afterIdx = 0;
  while (beforeIdx < beforeArr.length || afterIdx < afterArr.length) {
    // 前后都有
    if (beforeIdx < beforeArr.length && afterIdx < afterArr.length) {
      if (beforeArr[beforeIdx] < afterArr[afterIdx]) {
        resultArr.push(beforeArr[beforeIdx]);
        beforeIdx++;
      } else {
        resultArr.push(afterArr[afterIdx]);
        afterIdx++;
      }
    } else if (beforeIdx < beforeArr.length) {
      // 前还有
      resultArr.push(beforeArr[beforeIdx]);
      beforeIdx++;
    } else {
      resultArr.push(afterArr[afterIdx]);
      afterIdx++;
    }
  }
  return resultArr;
}

性能测试

// Prepare
var ARRAY_LENGTH = 10000;
var MAX_VALUE = ARRAY_LENGTH * 10;
var arr = new Array(ARRAY_LENGTH).fill(0).map(x => Math.floor(Math.random() * MAX_VALUE));
console.log('original array', arr);

// Test quick sort
console.time('quick sort');
console.log('after quick sort', quickSort(arr));
console.timeEnd('quick sort');

// Test bulle sort
console.time('bulle sort');
console.log('after bulle sort', bubbleSort(arr));
console.timeEnd('bulle sort');

// Test select sort
console.time('select sort');
console.log('after select sort', bubbleSort(arr));
console.timeEnd('select sort');

// Test insertion sort
console.time('insertion sort');
console.log('after insertion sort', insertionSort(arr));
console.timeEnd('insertion sort');

// Test merge sort
console.time('merge sort');
console.log('after merge sort', mergeSort(arr));
console.timeEnd('merge sort');

Sqlite Helper

class SQLiteClient {
  constructor(db) {
    this.db = db;
  }

  beginTransaction() {
    return this._exec('BEGIN TRANSACTION;');
  }

  commitTransaction() {
    return this._exec('COMMIT TRANSACTION;');
  }

  rollbackTransaction() {
    return this._exec('ROLLBACK TRANSACTION;');
  }

  executeQuery(sql, params) {
    return this._execute('all', sql, params);
  }

  executeNonQuery(sql, params) {
    return this._execute('run', sql, params)
      .then(result => {
        return result.changes;
      });
  }

  executeScalar(sql, params) {
    return this._execute('get', sql, params);
  }

  executeInsert(sql, params) {
    return this._execute('run', sql, params)
      .then(result => {
        return result.lastID;
      });
  }

  _execute(type, sql, params) {
    if (!sql) {
      throw new Error('SQL not found.');
    }
    return new Promise((resolve, reject) => {
      // Process dynamic sql param
      sql = sql.replace(/#[a-zA-Z0-9]+/g, (match, offset, source) => {
        return params[match.slice(1)] || '';
      });
      // Not allow surplus parameters, Need get the used parameter keys
      let sqlNeedParamKeys = (sql.match(/@[a-zA-Z0-9]+/g) || []).map(x => x.slice(1));
      params = params || {};
      let sqlParams = {};
      // Process parameters
      sqlNeedParamKeys.forEach(k => {
        sqlParams[`@${k}`] = params[k];
      });

      this.db[type](sql, sqlParams, function (err, row) {
        if (err) { return reject(err) }
        if (type === 'run') {
          row = {
            lastID: this.lastID,
            changes: this.changes
          };
        }
        resolve(row);
      });
    });
  }

  // Execute sql
  _exec(sql) {
    return new Promise((resolve, reject) => {
      this.db.exec(sql, (err, row) => {
        if (err) { return reject(err) }
        resolve();
      });
    });
  }
}

module.exports = SQLiteClient;

如何移除Git SubModule

0. mv a/submodule a/submodule_tmp

1. git submodule deinit -f -- a/submodule    
2. rm -rf .git/modules/a/submodule
3. git rm -f a/submodule
# Note: a/submodule (no trailing slash,尾巴上没有斜杠)

# or, if you want to leave it in your working tree and have done step 0
3.   git rm --cached a/submodule
# 还原目录
mv a/submodule_tmp a/submodule 

算法:移除已排序数组中的重复元素

function removeDuplicates(nums) {
  if (!nums || nums.length === 0) {
    return 0;
  }
  let len = nums.length;
  let currentLen = 1;
  let current = nums[0];
  for (var i = 1; i < len; i++) {
    if (nums[i] !== current) {
      currentLen += 1;
      current = nums[i];
      nums[currentLen - 1] = nums[i];
    }
  }
  nums.length = currentLen;
  return currentLen;
}

var nums = [1, 1, 2];
console.log(nums, removeDuplicates(nums));
nums = [0, 0, 1, 1, 1, 2, 2, 3, 3, 4];
console.log(nums, removeDuplicates(nums));

利用Node脚本构建Docker镜像

var SSH = require('simple-ssh');
var argv = require('yargs').argv;

var ssh = new SSH({
  host: '11.11.11.11',
  user: 'root',
  pass: 'xxx',
  baseDir: '/opt/docker-builds/'
});

var opt = {
  out: function (stdout) {
    console.log(stdout);
  },
  err: function (stderr) {
    console.error(stderr);
  }
};

var out = function (stdout) {
  console.log(stdout);
}

const name = argv.name || argv.n;
const version = argv.version || argv.v;

if(!name || !version){
  return console.error('must provide --name(-n) and --version(-v)');
}

const projectFolder = name;
const projectName = `jay/${name}`;
const versionNo = version;

ssh.exec(`docker build -t ${projectName}:${versionNo} ${projectFolder}`, opt)
  //.exec(`docker push xxx.com/${projectName}:${versionNo}`, opt) // 没有仓库需要注销
  .start();

EditorConfig 配置

root = true

[*]
charset = utf-8

indent_style = space
indent_size = 2
tab_width = 2

end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

最长不重复子串算法-初版

function lengthOfLongestSubstring(text) {
  function hasRepeatChar(str) {
    var strArr = str.split('');
    var obj = {};
    strArr.forEach(x => (obj[x] = true));
    return strArr.length != Object.keys(obj).length;
  }

  var longStr = '';
  var len = text.length;
  var tempStr = '';
  for (var i = 0; i < len - longStr.length; i++) {
    tempStr = text[i];
    for (var j = i + 1; j < len; j++) {
      if (hasRepeatChar(tempStr + text[j])) {
        if (longStr.length < tempStr.length) {
          longStr = tempStr;
        }
        break;
      } else {
        tempStr += text[j];
      }
    }
    if (!hasRepeatChar(tempStr)) {
      if (longStr.length < tempStr.length) {
        longStr = tempStr;
      }
    }
  }
  // console.log(longStr);
  return longStr.length;
}
var len;
len = lengthOfLongestSubstring('abcdefghijklmn');
console.log(len, len === 14);
len = lengthOfLongestSubstring('cbca');
console.log(len, len === 3);
len = lengthOfLongestSubstring('c');
console.log(len, len === 1);

Nginx托管单页配置

location / {
  root /dist;
  try_files $uri $uri/ /index.html; # process history
  error_page 404 /index.html; #process history
}

Nginx gzip常规配置

放在

http {

}

中,

gzip on;
gzip_min_length 1k;
gzip_buffers 16 64k;
gzip_http_version 1.1;
gzip_comp_level 4;
gzip_types text/plain application/javascript text/css application/xml;
gzip_vary on;

webpack支持与VSC智能提示

通过 jsconfig.json 来实现,核心配置如下:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "target": "ES6",
    "module": "commonjs",
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules"
  ]
}

Prettier常规配置

在根目录新建:.prettierrc.js,内容如下:

module.exports = {
  parser: 'babylon',
  printWidth: 120, // 每行最大120字符
  semi: true, // 末尾分号
  singleQuote: true, // 使用单引号
  overrides: [
    {
      files: ['*.json', '.eslintrc', '.tslintrc', '.prettierrc', '.tern-project'],
      options: {
        parser: 'json',
        tabWidth: 2
      }
    },
    {
      files: '*.{css,sass,scss,less,styl}',
      options: {
        parser: 'css',
        tabWidth: 2
      }
    },
    {
      files: '*.ts',
      options: {
        parser: 'typescript'
      }
    }
  ]
};

Android 分布式打包分析

apt-get update -qq > /dev/null

# 安装依赖库
apt-get update && apt-get install -y --no-install-recommends apt-utils > /dev/null
apt-get install -qq --no-install-recommends \
        build-essential \
        autoconf \
        curl \
        git \
        lib32stdc++6 \
        lib32z1 \
        lib32z1-dev \
        lib32ncurses5 \
        libc6-dev \
        libgmp-dev \
        libmpc-dev \
        libmpfr-dev \
        libxslt-dev \
        libxml2-dev \
        m4 \
        ncurses-dev \
        ocaml \
        openjdk-8-jdk \
        openssh-client \
        pkg-config \
        python-software-properties \
        ruby-full \
        software-properties-common \
        unzip \
        wget \
        zip \
        zlib1g-dev > /dev/null

# 安装Node
curl -sL -k https://deb.nodesource.com/setup_${NODE_VERSION} \
        | bash - > /dev/null && \
    apt-get install -qq nodejs > /dev/null

apt-get clean > /dev/null && \
    rm -rf /var/lib/apt/lists/ && \


npm install --quiet -g npm > /dev/null && \
    npm install --quiet -g react-native-cli > /dev/null && \
    npm cache clean --force > /dev/null

echo "installing fastlane" && \
    gem install fastlane --quiet --no-document > /dev/null

# Get the latest version from https://developer.android.com/studio/index.html
ENV ANDROID_SDK_TOOLS_VERSION="3859397"

# Get the latest version from https://developer.android.com/ndk/downloads/index.html
ENV ANDROID_NDK_VERSION="15c"


ENV ANDROID_HOME="/opt/android-sdk" \
    ANDROID_NDK="/opt/android-ndk" \
    JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/

# 安装sdk Tools
echo "installing sdk tools" && \
    wget --quiet --output-document=sdk-tools.zip \
        "https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_TOOLS_VERSION}.zip" && \
    mkdir --parents "$ANDROID_HOME" && \
    unzip -q sdk-tools.zip -d "$ANDROID_HOME" && \
    rm --force sdk-tools.zip

# 安装ndk
echo "installing ndk" && \
    wget --quiet --output-document=android-ndk.zip \
    "http://dl.google.com/android/repository/android-ndk-r${ANDROID_NDK_VERSION}-linux-x86_64.zip" && \
    mkdir --parents "$ANDROID_NDK_HOME" && \
    unzip -q android-ndk.zip -d "$ANDROID_NDK" && \
    rm --force android-ndk.zip && \

# Install SDKs
# Please keep these in descending order!
# The `yes` is for accepting all non-standard tool licenses.

mkdir --parents "$HOME/.android/" && \
    echo '### User Sources for Android SDK Manager' > \
        "$HOME/.android/repositories.cfg" && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager --licenses > /dev/null && \
    echo "installing platforms" && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager \
        "platforms;android-26" \
        "platforms;android-25" \
        "platforms;android-24" \
        "platforms;android-23" \



echo "installing platform tools " && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager \
        "platform-tools"

echo "installing build tools " && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager \
        "build-tools;26.0.2" "build-tools;26.0.1" "build-tools;26.0.0" \
        "build-tools;25.0.3" "build-tools;25.0.2" \
        "build-tools;25.0.1" "build-tools;25.0.0" \
        "build-tools;24.0.3" "build-tools;24.0.2" \
        "build-tools;24.0.1" "build-tools;24.0.0" \
        "build-tools;23.0.3" "build-tools;23.0.2" "build-tools;23.0.1"

echo "installing extras " && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager \
        "extras;android;m2repository" \
        "extras;google;m2repository"

echo "installing play services " && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager \
        "extras;google;google_play_services" \
        "extras;m2repository;com;android;support;constraint;constraint-layout;1.0.2" \
        "extras;m2repository;com;android;support;constraint;constraint-layout;1.0.1"


echo "installing Google APIs" && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager \
        "add-ons;addon-google_apis-google-24" \
        "add-ons;addon-google_apis-google-23" \
        "add-ons;addon-google_apis-google-22" \
        "add-ons;addon-google_apis-google-21"


# 安装Git
apt-get install git

https://github.com/mingchen/docker-android-build-box/blob/master/Dockerfile

ReactNative 问题汇总

Collection the react native questions.

1. TouchableWithoutFeedback onPress 不生效?

原因分析: TouchableWithoutFeedback 需要 <View> 作为直接子集,如果children不是<View />,则不会生效,举例如下:

const Hello = props => <View><Text>Hello</Text></View>;
// Not working
<TouchableWithoutFeedback onPress={()=>alert('working')}>
  <Hello />
</TouchableWithoutFeedback>

// Working
<TouchableWithoutFeedback onPress={()=>alert('working')}>
  <View>
    <Hello />
  </View>
</TouchableWithoutFeedback>

2. Android机型,在长列表下,部分远程图片不显示(确认请求成功、图片没问题,Image组件已经设置固定宽高,加载的图片尺寸远大于容器大小)

原因分析: 由于图像远大于视图,所以在加载该类图片时,容易在低端机型上导致内存不足。解决办法是设置 resizeMethod=resize(默认为auto)。详情,请参考:https://facebook.github.io/react-native/docs/image.html#resizemethod

利用Object实现简易Map

class Map {
  constructor() {
    this.$keyObj = {};
    this.$valueObj = {};
    this.$length = 0;
  }
  set(key, value) {
    const autoKey = `key${Map.idx++}`;   
    this.$keyObj[autoKey] = key;
    this.$valueObj[autoKey] = value;
    // 需要判断是否覆盖来控制 $length
  }
  _getAutoKey(key) {
    const keyItem = Object.entries(this.$keyObj).find(x => x[1] === key);
    return keyItem[0];
  }
  get(key) {
    const autoKey = this._getAutoKey(key);
    if (!autoKey) {
      return undefined;
    }
    return this.$valueObj[autoKey];
  }
}

Map.idx = 1;

// Usage

var map = new Map();
var key = new Object();
map.set(key, 1);
console.log(map.get(key), map.get(key) === 1);

实现简单的并发请求控制

题目:请实现如下的函数,可以批量请求数据,所有的URL地址在 urls 参数中,同时可以通过 max 参数控制请求的并发数,当所有的请求结束之后,需要执行 callback 回调函数。发请求的函数可以直接使用 fetch 即可。

function sendRequest(urls: string[], max: number, callback: () => void){
}

NodeJS:简单实现一个静态服务器

const fs = require('fs');
const path = require('path');
const http = require('http');
const util = require('util');

const MIME_MAP = {
  '.js': 'text/javascript',
  '.css': 'text/css',
};

const WEB_ROOT = path.join(__dirname, 'webroot');

const server = http.createServer((req, res) => {
  const { url } = req;
  let fileUrl = '';
  if (/\.[a-zA-Z0-9]+$/.test(url)) {
    fileUrl = path.join(WEB_ROOT, url);
  } else {
    fileUrl = path.join(WEB_ROOT, 'index.html');
  }
  util
    .promisify(fs.exists)(fileUrl)
    .then(isExists => {
      if (!isExists) {
        res.write('404');
        return res.end();
      }
      const extName = path.extname(fileUrl);
      const mimeType = MIME_MAP[String(extName).toLowerCase()];
      if (mimeType) {
        res.writeHead(200, { 'content-type': mimeType });
      }
      fs.createReadStream(fileUrl).pipe(res);
    });
});

server
  .listen(80, () => {
    const addr = server.address();
    console.info('server started...', addr);
  })
  .on('error', console.error);

致各位找工作的小伙伴

  • 公司不是慈善机构,不会让你进去再学;
  • 不要和面试官说,我相信我自己肯定能行,公司需要的是你现在能行;
  • 未毕业/刚毕业,没有工作经验,但如果项目经验多也是加分项;
  • 证书(不是指毕业证)大多数无用,但如果是国际性/国家级的技能比赛证书,也是很好的加分项;
  • 潜力(学习能力)很重要,不怕你暂时不会,但就怕你学不会;
  • 如果有机会,维护好自己的github,有些公司比较看重;
  • 切勿好高骛远,切勿眼高手低;

REST API状态码设计

正常请求

直接返回具体的业务数据,HTTP状态码根据具体的场景列举如下:

  • 200 最常用,返回数据
  • 201 如果是创建资源成功,则使用201
  • 202 如果是更新或删除资源成功,则使用202
  • 204 不想返回任何内容,则可以使用204

异常请求

业务异常

  • 400 错误的请求,可能是参数不对
  • 401 未授权
  • 403 禁止访问
  • 404 找不到资源

服务端标准错误

  • 500 直接扔标准的500错误

异常数据格式

{
    status: 401, // 和HTTP状态码一致
    code: '201452', // 业务定义的错误代码
    message: 'Unauthorized', // 错误信息
    stack: null // 区分环境,确认是否输出
}

附Express中的错误处理逻辑:

app.use((req, res, next) => {
  next({
    status: 404,
    code: '404',
    message: '404 Not Found.'
  });
});
app.use((err, req, res, next) => {
  let status = 500;
  let message = '';
  let code = '500';
  let stack = null;
  // 简单业务错误
  if (typeof err === 'string') {
    status = 400;
    code = '400';
    message = err;
  } else if (err.isJoi) {// 请求验证错误
    status = 400;
    code = '400';
    message = err.details.map(x => x.message).join('\n');
  } else if (err instanceof Error) { // 标准错误处理
    if (err.code) {
      code = err.code;
    }
    message = err.message;
    stack = err.stack;
  } else { // Next({status: 400, code: 'xxx'}) 自定义错误
    status = err.status || 400;
    code = err.code || '400';
    message = err.message;
  }
  res.status(status).json({
    status,
    code,
    message,
    stack
  });
});

实验代码

我有一个用来验证技术点和语法使用的项目。要不要考虑下将这个文档项目升级升级?

H5键盘收缩监控

// 初版
export const keyboardUtil = {
  isIphone() {
    return false;
  },
  init() {
    const originalHeight = document.documentElement.clientHeight || document.body.clientHeight;
    window.onresize = function resize() {
      // 键盘弹起与隐藏都会引起窗口的高度发生变化
      const resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
      if (resizeHeight < originalHeight) {
        alert('展开');
      } else {
        alert('收起');
      }
    };

    document.body.addEventListener('focusin', () => {
      // 软键盘弹出的事件处理
      if (this.isIphone()) {
        alert('展开');
      }
    });
    document.body.addEventListener('focusout', () => {
      // 软键盘收起的事件处理
      if (this.isIphone()) {
        alert('收起');
      }
    });
  }
};

keyboardUtil.init();

Mysql Helper

class MysqlClient {
  constructor(pool) {
    this.pool = pool;
  }

  /**
   * Begin database transaction
   */
  beginTransaction() {
    return this._getConnection()
      .then(conn => {
        return new Promise((resolve, reject) => {
          conn.beginTransaction(err => {
            if (err) { return reject(err); }
            conn.inTransaction = true;
            resolve(conn);
          })
        });
      });
  }

  /**
   * Commit transaction
   * @param {any} conn 
   */
  commitTransaction(conn) {
    return new Promise((resolve, reject) => {
      conn.commit(err => {
        if (err) {
          conn.rollback(() => {
            this._releaseConnection(conn, true);
            reject(err);
          });
        } else {
          this._releaseConnection(conn, true);
          resolve();
        }
      });
    });
  }

  /**
   * Rollback transaction
   * @param {any} conn 
   */
  rollbackTransaction(conn) {
    return new Promise((resolve, reject) => {
      conn.rollback(() => {
        this._releaseConnection(conn, true);
        resolve();
      });
    });
  }

  /**
   * Get a database connection
   */
  getConnection() {
    return this._getConnection();
  }

  /**
   * Execute sql, return query result(array)
   * @param {string} sqlString 
   * @param {object | array} values 
   * @param {any} conn 
   */
  executeQuery(sqlString, values, conn = null) {
    return this._execute(sqlString, values, conn);
  }

  /**
   * Execute sql, return single result(the first one)
   * @param {string} sqlString 
   * @param {object | array} values 
   * @param {any} conn 
   */
  executeScalar(sqlString, values, conn = null) {
    return this._execute(sqlString, values, conn)
      .then(results => {
        if (results.length === 0) {
          return null;
        }
        return results[0];
      });
  }

  /**
   * Execute sql, return affected rows
   * @param {string} sqlString 
   * @param {object | array} values 
   * @param {any} conn 
   */
  executeNonQuery(sqlString, values, conn = null) {
    return this._execute(sqlString, values, conn)
      .then(results => {
        return results.affectedRows;
      });
  }

  /**
   * Execute sql, return insertId(for auto id)
   * @param {string} sqlString 
   * @param {object | array} values 
   * @param {any} conn 
   */
  executeInsert(sqlString, values, conn = null) {
    return this._execute(sqlString, values, conn)
      .then(results => {
        return results.insertId;
      });
  }

  /**
 * private function, get db connection
 */
  _getConnection() {
    return new Promise((resolve, reject) => {
      this.pool.getConnection((err, conn) => {
        if (err) { return reject(err); }
        resolve(conn);
      });
    });
  }

  /**
   * Release connection
   * @param {any} conn 
   * @param {boolean} closeTran 
   */
  _releaseConnection(conn, closeTran = false) {
    if (closeTran) {
      conn.inTransaction = false;
    }
    conn.release();
  }

  /**
   * Execute sql, return resuluts;
   * @param {string} sqlString 
   * @param {object|array} values 
   * @param {any} conn 
   */
  _execute(sqlString, values, conn) {
    let { sql, params } = this._processSqlAndParameter(sqlString, values);
    let p = conn ? Promise.resolve(conn) : this._getConnection();
    return p.then(conn => {
      return new Promise((resolve, reject) => {
        conn.query(sql, params, (err, results, fields) => {
          // If conn is in transaction, not release
          if (!conn.inTransaction) {
            this._releaseConnection(conn);
          }
          if (err) { return reject(err); }
          resolve(results);
        });
      });
    });
  }

  _processSqlAndParameter(sqlString, params) {
    let result;
    // If is an array, direct return.
    if (Array.isArray(params)) {
      result = {
        sql: sqlString,
        params: params.slice()
      };
    } else {
      // Replace object to array, and use ? replace @Property
      let paramArr = [];
      if (params) {
        let paramKeys = Object.keys(params);
        sqlString = sqlString.replace(/@[a-zA-Z0-9]+/g, (match, offset, str) => {
          let matchKey = match.replace('@', '');
          if (paramKeys.indexOf(matchKey) >= 0) {
            paramArr.push(params[matchKey]);
            return '?';
          }
          return match;
        });
      }
      result = {
        sql: sqlString,
        params: paramArr
      };
    }
    return result;
  }
}

module.exports = MysqlClient;

ReduxHelper

import { connect } from 'react-redux';
import { combineReducers, createStore } from 'redux';

const reducerMap = {};

export const reduxHelper = {
  store: null, // 缓存全局store
  _isFunction(fn) {
    return typeof fn === 'function';
  },
  /**
   * 创建Reducer的辅助方法
   * @param {object} initialState  默认state
   * @param {*} reducerObj
   */
  createReducer(initialState, reducerObj) {
    return (state = initialState, action) => {
      console.log('action', action.type);
      const reducerFn = reducerObj[action.type];
      if (this._isFunction(reducerFn)) {
        return reducerFn.call(null, state, action.payload);
      }
      return state;
    };
  },

  /**
   * 创建页面
   * @param {*} pageState
   * @param {*} viewComponent
   */
  createPage(pageState, viewComponent) {
    const self = this;
    reducerMap[pageState.namespace] = this.createReducer(pageState.state, pageState.reducers);
    function mapStateToProps(state) {
      const mapState = {};
      // 绑定页面的state属性
      Object.keys(pageState.state || {}).forEach(k => (mapState[k] = (state[pageState.namespace] || {})[k]));

      // 绑定用户定义的state属性
      let newCalcState = {};
      if (self._isFunction(pageState.mapStateToProps)) {
        newCalcState = pageState.mapStateToProps(state[pageState.namespace], this.store);
      }
      return { ...mapState, ...newCalcState };
    }
    function mapDispatchToProps(dispatch) {
      const mapDispatch = {};
      Object.keys(pageState.actions || {}).forEach(k => {
        const actionFn = pageState.actions[k];
        if (self._isFunction(actionFn)) {
          mapDispatch[k] = () => {
            actionFn(dispatch);
          };
        } else {
          console.warn(`key [${k}] not a actions`);
        }
      });
      return mapDispatch;
    }
    this.store && this.store.replaceReducer(combineReducers(reducerMap));
    return connect(mapStateToProps, mapDispatchToProps)(viewComponent);
  },

  createStore() {
    function reducer(state = {}, action) {
      return state;
    }
    this.store = createStore(reducer); // combineReducers(reducerMap)
    window.AppState = this.store;
    return this.store;
  }
};

一个缓存异步函数返回值的方法

V1 版本:

import { EventEmitter } from "events";
const bus = new EventEmitter();
// 缓存队列
const cacheMap: Map<
  string,
  {
    status: "pending" | "loading" | "succeed" | "failed";
    data?: any;
    queue: string[];
  }
> = new Map();

async function asyncCache(cacheKey: string, asyncFn: () => Promise<any>) {
  // 先初始化缓存
  if (!cacheMap.has(cacheKey)) {
    cacheMap.set(cacheKey, { status: "pending", queue: [] });
  }
  const fnId = Math.random().toString(16).slice(2);
  // 缓存对象,可直接修改对象属性
  let cacheItem = cacheMap.get(cacheKey);
  // 有缓存成功的数据,直接返回
  if (cacheItem.status === "succeed") {
    return cacheItem.data!;
  }

  // 加入队列
  cacheItem.queue.unshift(fnId);

  // 有请求中的数据,先加入队列
  if (cacheItem.status === "loading") {
    await new Promise((resolve) => {
      bus.on("ASYNC_DONE", () => {
        // 如果数据缓存成功或者队列中轮到自己,就停止等待
        if (
          cacheItem.status === "succeed" ||
          fnId === cacheItem.queue[cacheItem.queue.length - 1]
        ) {
          resolve(1);
        }
      });
    });
  }
  cacheItem = cacheMap.get(cacheKey);
  // 有缓存成功的数据,直接返回
  if (cacheItem.status === "succeed") {
    return cacheItem.data!;
  }
  cacheItem.status = "loading";
  return Promise.resolve()
    .then(() => {
      return asyncFn();
    })
    .then((data) => {
      // 记录缓存状态和缓存数据
      cacheItem.status = "succeed";
      cacheItem.data = data;
      return data;
    })
    .catch((reason) => {
      cacheItem.status = "failed";
      return Promise.reject(reason);
    })
    .finally(() => {
      // 结束了自己出队
      cacheItem.queue.pop();
      // 通知其他等待的请求
      bus.emit("ASYNC_DONE");
    });
}

VSC插件sort-import 的基本配置

 "importSort": {
    ".js, .jsx, .es6, .es,": {
      "parser": "babylon",
      "style": "module-compact"
    },
    ".ts, .tsx": {
      "parser": "typescript",
      "style": "eslint",
      "options": {}
    }
  },

配置到package.json中。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.