Giter VIP home page Giter VIP logo

blog's People

Contributors

sabakugaara avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar

Forkers

chen1243624551

blog's Issues

let 和 var 的区别?下次这么回答

letvar 的区别?

这是一个入门级的面试题,回答也很简答:let 具备块级作用域,var 不是。

不仅仅是 Block

首先,什么是块级作用域?简单理解就是一切被花括号 {} 包裹的代码。例如:

let foo = 1;
{
   let foo = 2;
}
console.log(foo); // 输出: 1

花括号被广泛的用于函数、for 循环、try catch,所以这些都具备块级作用域。但是 let 不仅仅在块级作用域有区别,例如猜猜看下面这段循环会如何执行?

for (let i = 0; i < 10; i++) {
    let i = 'Ozz';
     console.log(i);
}

会打印 10 行字符串,然后循环结束 (你也可以换成 var 试试),说明圆括号 表达式 中的 let 也具备独立的作用域,和循环体中的 i 变量互不影响。

let 不会变量提升

let 定义的变量不会变量提升,即:只能在声明之后使用

var 的变量声明,会被提升:

hoist = 'foo';
console.log(hoist); // 输出 foo
var hoist;

这段代码等价于:

var hoist;
hoist = 'foo';
console.log(hoist); // 输出 foo

let 则不行:

notHoist = 'bar'; // 抛出 ReferenceError,不能提前使用
let notHoist;

let 不会污染 window

浏览器环境下,var 声明的变量会挂载到 window 对象上,let 不会。

var foo = 'xxx';
let bar = 'zzz';

console.log(window.foo); // 输出 xxx
console.log(window.bar); // undefined

小心 typeof

常常会用 typeof 判断一个变量是否定义,再决定是否初始化。但是let 配合时,要小心了!!!

let a = typeof a === 'undefined' ? {} : a;

上面这段代码会直接抛出异常 ReferenceError: a is not defined,可以调整成:

let a;
a = typeof a === 'undefined' ? {} : a;

weight random: 权重轮询算法

js 实现

function randomByWeight(elements) {
  if (!Array.isArray(elements) || !elements.length) {
    return null;
  }
  const totalWeight = elements.reduce((sum, x) => sum + x.weight, 0);

  if (totalWeight && elements.length) {
    let offset = Math.random() * totalWeight;
    for (let index = 0; index < elements.length; index++) {
      offset -= elements[index].weight;
      if (offset < 0) {
        return elements[index];
      }
    }
  }

  return elements[elements.length - 1];
};

// 权重分别为 1 2 3 4
const ele = [
    { element: 'a', weight: 1 }, 
    { element: 'b', weight: 2 },
    { element: 'c', weight: 3 },
    { element: 'd', weight: 4 }
];
const result = {
    a: 0,
    b: 0,
    c: 0,
    d: 0,
};

function test() {
    const r = randomByWeight(ele, 10);
    result[r.element]++;
}

for(let i = 0; i < 1000; i++) {
    test();
}

console.log(result);

参考

block VS inline-block VS inline

width & height

  • block 可以设置宽高,不管内部内容实际需要多少宽度,默认始终占满一行
  • inline-block 可以设置宽高,但宽度默认为 width: auto,根据内容需要多少,就占据多少宽度,当然也可以手动指定宽度
  • inline 则无法设置宽度和高度,内容需要多宽就占据多宽

margin

  • block 和 inline-block 都可以设置 margin-top/left/right/bottom,但是:

两个相邻的块级元素,第一行设置 margin-bottom,第二行设置 margin-top, 二者是会重叠的:两个块级元素的实际间距,是取 margin-bottommargin-top 两者的最大值。而 inline-block 则是上下两个 margin 值的和 示例请戳

  • inline 则无法设置 margin-top/bottom ,但是可以设置 margin-left/right

常用的 margin: 0 auto 居中,也只能用于 block 级别元素,对 inline-block 是无效的

padding

  • block 和 inline-block 都可以设置 padding-top/left/right/bottom
  • inline 可以设置 padding-top/bottom,会影响到元素的边框。但是会被前后相邻的块级元素忽略,导致重叠在一起。所以非常不推荐使用 示例请戳

Nginx tcp/udp 负载均衡配置

操作步骤见官方文档:https://www.nginx.com/resources/admin-guide/tcp-load-balancing/

有几个参数需要注意:

  • proxy_timeout: 链接建立成功后,若没有数据发送,超过该参数指定时间后,便会关闭该链接。针对配置好的 tcp 代理,可以用 telnet 测试:1. 链接成功后,不发送任何数据,达到 proxy_timeout 时间后,链接会被关闭;2. 链接成功后,持续写入任意数据,链接不会被关闭。

    这个值需要比应用层设置的链接超时时间长,才合理。

  • fails_timeout: 包括 upstream 被 nginx 标记不可用的持续时间和发生失败时重试的时间(达到 max_fails 后不再重试)

  • max_fails: 是指 nginx 尝试和 upstream 建立链接时,发生错误或超时的最大次数。达到后,标记该 upstream 不可用,新链接会使用其他 upstream。

负载均衡算法

  • round-robin 轮询,默认值,不需要配置
  • least_conn 最小连接数:新链接会发往后端连接数最少的一个 upstream
  • least_time 最小负载:其可选值为 connect first_byte last_byte
  • hash 可以配置根据客户端 ip hash,hash $remote_addr;

以 async/await 为例,说明 babel 插件怎么搭

你一定碰到过这些库

babel-polyfill

项目地址:https://github.com/babel/babel/blob/master/packages/babel-polyfill

通过两个依赖实现功能

  • core-js/shim 提供 ES5/6/7 标准方法的实现
  • regenerate-runtime 提供 async 语法编译后的的运行时环境(下文会专门说明)

babel-plugin-transform-runtime

项目地址:https://github.com/babel/babel/blob/master/packages/babel-plugin-transform-runtime

开发 ES6/7 新特性的库推荐使用该插件,需要注意的是,安装时,必须同时安装 babel-runtime 作为依赖:

npm install --save-dev babel-plugin-transform-runtime
npm install --save babel-runtime // `babel-plugin-transform-runtime` 插件本身其实是依赖于 `babel-runtime` 的,但为了适应 `npm install --production` 强烈建议添加该依赖。

插件会将 es6/7 的语法转化为 es5 兼容的格式,并提供运行时依赖。什么是运行时依赖?比如你要用 Array.from 方法,该方法的具体实现必须在代码的执行环境中提供,这就是运行时依赖。

该插件在转化语法时,不会污染全局环境。而 babel-polyfill 则会污染全局环境。

babel-plugin-external-helpers

项目地址:https://github.com/babel/babel/blob/master/packages/babel-plugin-external-helpers/

代码很少,只依赖于 babel-runtime。相比较 babel-plugin-transform-runtime 会在每个模块注入运行时代码,该插件会将运行时代码打包,类似封装到一个对象下,这样避免注入重复的代码。

让 async/await 跑起来

通过最简单的一个函数:

async function foo() {
  return await 1
}

foo().then(function(val) {
  console.log(val)  // should output 1
})

说明这些 babel 插件怎么搭配,三种方案:

方案一:regenerator

.babelrc 如下配置:

{
  "plugins": ["transform-runtime", "babel-plugin-transform-regenerator", "babel-plugin-transform-es2015-modules-commonjs"]
}
  • babel-plugin-transform-regenerator 将 async/await 语法转化成 regenerator 库支持的语法
  • transform-runtime 将运行时注入,类似:import regenerator from 'babel-runtime/regenerator'
  • babel-plugin-transform-es2015-modules-commonjs 只是为了将 import 转化为 require,便于在 node.js 模块下执行(如果你的执行环境支持 es6 的模块机制,则不需要该插件)。

方案二:generator

这种方式,最适合 node.js 环境,node.js 最早从 0.11 开始,便支持 generator。.babelrc 如下配置:

{
  "plugins": ["babel-plugin-transform-async-to-generator"]
}

生成的代码,在 node.js 环境下可以直接执行,此时便不再需要 babel 提供任何有关 generator 相关的运行时环境了,直接 node.js 自带~

方案三:babel-polyfill

.babelrc 如下配置:

{
  "plugins": ["babel-plugin-transform-regenerator"]
}

其实和前面 regenerate 一样,去掉了 runtime 配置。编译结束后,需要手动在结果文件的第一行加入:

require('babel-polyfill')

通过 babel-polyfill 向全局注入运行时依赖。那什么时候该用 babel-polyfill 什么时候用 babel-runtime?官网给出了解释:

This will emulate a full ES2015+ environment and is intended to be used in an application rather than a library/tool.

  • 如果是应用级别的开发,可以考虑使用 babel-polyfill:大而全,支持所有的 es2015+ 特性。可以在项目入口处统一添加,也可以通过打包工具配置入口。
  • 如果是开发一个库,使用 babel-runtime,不会污染全局,而且是根据情况注入需要的运行时环境。

关于 babel-runtime 更多细节,强烈建议阅读官方文档:https://github.com/babel/babel/blob/master/packages/babel-plugin-transform-runtime/README.md

别忘了 externel-helpers

刚刚只是一个简单的 foo 函数,一个文件。多个文件时,存在每个文件都注入类似 asyncToGenerator 等辅助方法,导致重复。举例说明:

foo.js

'use strict'

const bar = require('./bar')

async function foo () {
  const val = await bar()
  console.log(val)
}

foo()

bar.js

'use strict'

module.exports = async function bar () {
  return await 'bar'
}

采用前文提到的 generator 方式,去编译,会发现结果文件中,都有 _asyncToGenerator 定义。修改 .babelrc 如下:

{
  "plugins": ["babel-plugin-transform-async-to-generator", "babel-plugin-external-helpers"]
}

再编译,_asyncToGenerator 都变成了 babelHelpers.asyncToGenerator。这样,多个模块之间没有重复的代码注入,更加干净清爽。不过此时 babelHelpers 是未定义,仍然需要引入运行时环境: transform-runtime,最终可以运行的配置如下:

{
  "plugins": [
    "babel-plugin-transform-async-to-generator",
    "babel-plugin-external-helpers",
    "transform-runtime",
    "babel-plugin-transform-es2015-modules-commonjs"
  ]
}

示例代码见:https://github.com/sabakugaara/babel-example

glob 和命令行匹配冲突

tape 官方文档有这么一句话:

tape's arguments are passed to the glob module. If you want glob to perform the expansion on a system where the shell performs such expansion, quote the arguments as necessary:

$ tape 'tests/**/*.js'
$ tape "tests/**/*.js"

即:如果希望 glob 生效,需要将参数使用单引号或双引号括起来,原因是:若不括起来,shell 会执行一次范匹配查询。见 #2

tape 解析的参数差异如下:

  • 有单双引号,{r: [], require: [], _: 'tests/**/*.js'}
  • 无单双引号,{r: [], require: [], _: ['tests/foo/bar1.js', 'tests/foo/bar2.js']

参考

如何开发一个前后端通用的 js 类库

尽量选用纯 js 实现的库

要想开发一个前后端(浏览器 + node.js)都能运行的类库,首先要做的就是尽量不调用特定平台的 API,比如依赖浏览器端的 window 或服务端(本文特指 node.js 端) 的模块,例如 fs。在选择项目依赖的时候,也要注意使用前后端通用的类库。例如需要用到 md5,不能使用 crypto 模块,可以找 npm 纯 js 实现的包:md5

browser 字段定义浏览器端加载的模块别名

实际开发中,肯定会有些特定的实现依赖不同的平台。可以把这些不同平台的实现放入不同文件,然后在 package.json 文件中添加 browser 字段,定义浏览器端使用的模块。

假设实现一个工具模块 utils.js:模块的每个方法实现依赖不同的平台,例如 getFileSize 在浏览器端,可以通过 File API实现;在服务端,则是通过 node.js fs 模块实现。此时 package.json 中可以这么定义:"browser": {"./utils.js": "browser-utils.js"} 。类库中统一使用 import utils from "./utils" 来引用,最后打包工具会根据不同的构建环境,进行替换。

其他用法,例如:

  • "browser": "browser/index.js": 浏览器环境下使用 browser/index.js 替代 main 字段指定的入口文件
  • "browser": {"./src/utils.js": "./browser/uitls.js"}: 浏览器环境下,类库中加载 utils.js 文件时,用 browser/utils.js 文件替代。

使用 browser 字段,需要注意,路径是相对于项目根目录的。

在打包项目时,例如 rollup-plugin-node-resolve 插件,可以通过配置 isBrowser 字段指定当前构建目标是浏览器环境还是服务端环境,如果是浏览器环境,便用 browser 字段指定的模块进行替换。webpack2 也支持通过 resolve.aliasFields 配置。

typeof window === 'undefined'

一些小的方法,可能没必要放到不同的文件中独立实现的话,可以通过判断当前环境是否是浏览器运行不同的逻辑:const isBrowser = typeof window === 'undefined'

自定义 V8 error stack

先来看一段代码

// 摘自 capn 包
var Capn = {};

var define = Object.defineProperty.bind(undefined, Capn);

define('stack', {
  get: function(){
    var originalStack = Error.prepareStackTrace;
    Error.prepareStackTrace = function(_, stack){ return stack; };
    var err = new Error();
    Error.captureStackTrace(err, arguments.callee);
    var stack = err.stack;
    Error.prepareStackTrace = originalStack;
    return stack;
  }
});

define('line', {
  get: function(){
    return this.stack[1].getLineNumber();
  }
});

define('typeName', {
  get: function(){
    return this.stack[1].getTypeName();
  }
});

define('fileName', {
  get: function(){
    return this.stack[1].getFileName();
  }
});

这段代码给 Capn 对象定义了几个属性,分别是 typeName fileName line stack

console.log(Capn.line) // 会输出该行代码所在行
console.log(Capn.fileName) // 会输出该行代码的文件名
console.log(Capn.typeName) // 会输出 Object

这一切,都依赖于 stack[1] 的值。stack 属性也是动态获取的。定义 stack 的方法很简单,
只调用了两个函数,一个是 captureStackTrace 另一个是 prepareStackTrace

如何实现的?

1 先来看看 captureStackTrace,node.js 文档的定义是

Creates a .stack property on targetObject, which when accessed returns a string representing the location in the code at which Error.captureStackTrace() was called.

const myObject = {};
Error.captureStackTrace(myObject);
myObject.stack;  // similar to `new Error().stack`

也就是说,在一个对象上,创建 stack 属性,它的值等价于 new Error().stack。第二个参数是一个函数,所有在这个函数调用之后的调用栈都会被隐藏掉。通过下面的示例代码

function foo() {
  function bar() {
    var err = new Error()
    // Error.captureStackTrace(err, foo) // 试着去掉这行,看看区别
    return err
  }
  return bar()
}
var e = foo();
console.log(e.stack);

会发现,增加了 captureStackTrace 后,错误栈只会到 var e = foo() 这一行,剩余的都没有了

2 再来看看 prepareStackTrace,详见Customizing stack traces,可以简单模拟系统错误栈输出如下:

function foo() {
  function bar() {
    var err = new Error()
    Error.prepareStackTrace = function(_, stack){
      return stack.reduce((result, line) => {
            result += '  at ' + line.getFunctionName() + '(' + line.getFileName() + ':' + line.getLineNumber() + ')\n';
        return result;
      }, '');
    };
    return err;
  }
  return bar()
}
var e = foo();
console.log(e.stack);

Capn 里的 prepareStackTrace 没有做别的事情,直接返回错误栈(CallSite)队列,以获取 Capn.line 当前代码行数为例,栈的最顶层是定义 line 属性的 get 方法调用,次之是 Capn.line 调用。所以取 stack[1].getLineNumber() 便可以拿到调用处的代码行数。如果没有 captureStackTrace 那么取 stack[2] 即可

需要注意,这个只适合 V8 平台。

其他平台兼容

参见 https://github.com/inf3rno/error-polyfill,不过作者不推荐使用,原理是通过反向解析 error.stack 字符串,然后模拟 V8 下的函数

loop invariant:一段 for 循环优化代码

偶然看到一个代码提交里,针对 for 循环还做了优化,将数组长度的取值移到了循环外,代码如下:

for (let i = 0, len = arr.length; i < len; i++) {
  // loop
}

很久没见到这样的代码了,注意细节优化的人不多,不得不为提交的作者点赞 👍

但是(转折来了..),你需要停下来思考下:

  • 这个优化是否真的有用?
  • 如果有用的话,能带来多大的提升?

loop invariant

这类优化操作,概念称为:循环不变代码外提。编译器可以自动把这层优化做掉。

优化是否有用,直接浏览器里跑一跑测试代码就知道了:

function getTestArray(numEntries) {
    var testArray = [];
    for(var i = 0; i < numEntries; i++) {
        testArray.push(Math.random());
    }
    return testArray;
}

function testInVariable(testArray) {
    for (var i = 0; i < testArray.length; i++) {
        doSomethingAwesome(testArray[i]);
    }
}

function testInLoop(testArray) {
    var len = testArray.length;
    for (var i = 0; i < len; i++) {
        doSomethingAwesome(testArray[i]);
    }
}

function doSomethingAwesome(i) {
    return i + 2;
}

function runAndAverageTest(testToRun, testArray, numTimesToRun) {
    var totalTime = 0;
    for(var i = 0; i < numTimesToRun; i++) {
        var start = new Date();
        testToRun(testArray);
        var end = new Date();
        totalTime += (end - start);
    }
    return totalTime / numTimesToRun;
}

function runTests() {
    var smallTestArray = getTestArray(10000);
    var largeTestArray = getTestArray(10000000);

    var smallTestInLoop = runAndAverageTest(testInLoop, smallTestArray, 5);
    var largeTestInLoop = runAndAverageTest(testInLoop, largeTestArray, 5);
    var smallTestVariable = runAndAverageTest(testInVariable, smallTestArray, 5);
    var largeTestVariable = runAndAverageTest(testInVariable, largeTestArray, 5);

    console.log("Length in for statement (small array): " + smallTestInLoop + "ms");
    console.log("Length in for statement (large array): " + largeTestInLoop + "ms");
    console.log("Length in variable (small array): " + smallTestVariable + "ms");
    console.log("Length in variable (large array): " + largeTestVariable + "ms");
}

runTests();
runTests();
runTests();

从结果来看,基本上没有什么特别的提升。

参考

line-height & vertical-align 深入理解

本文源自css-font-metrics-line-height-and-vertical-align学习总结,希望更简单易懂

字体高度的定义

先上图,一行文字如何排版的:

2018-10-25 at 7 29 pm

  • x-height
    英文排版中,将字母 x 的高度称作 x-height。这个高度会做为字体排版的基准。
  • cap height
    大写字母高度,例如 H 或 I 的高度
  • ascender
    小写字母相比较 x-height 高出的高度
  • descender
    小写字母相比较 x-height 底部超出的部分
  • baseline
    基线,即 x-height 底部的水平线
  • meanline
    中线,即 x-height 顶部的水平线

字体高度 = ascender-height + x-height + descender-height

字体高度和 font-size 关系

font-size: 16px 并代表字体高度 16px。字体库设计时,会定义好字体高度。假设某字体库 A,其高度为 1600upm,
那么设置 font-size: 16px,浏览器在渲染时会根据字体高度进行缩放,实际高度:1600upm / 1000 * 16 = 25.6px。其中 1000 是字体库的基准大小。

所以,如果要使用字体库 A,并完美展示,至少需要 line-height 不低于 25.6px。

line-height 是如何计算的?

简单理解:行高默认恰好能够承载其若干行内元素。先上图(原图见英文原文):

2018-10-25 at 8 01 pm

图片说明:

  • 图中一共三行,第二行有若干不同的行内元素。不同的行内元素默认基于 vertical-align: baseline 对齐(图中蓝色线条)
  • 第二行明显比另外两行要高,因为其内部不同的行内元素高度不同,所以被撑开

vertical-align 如何对齐?

详细完整的解释,建议看 mdn

  • middle:父元素的 baseline 高度加上父元素的 x-height 高度的一半
  • text-bottom/text-top: 父元素的 descender/ascender line 对齐

总结

基于前面的解释,应该已经掌握基本的排版技巧。相信常见的问题会迎刃而解,例如:

  • 文字顶部被隐藏

line-height 小于字体高度展示所需的高度,所以常见设置为:line-height: 1.5。如果 line-height = font-size,会非常容易出现这个问题

  • 图片和文字不对齐
    image

截图取自 深入理解行内元素的布局示例

图片没有 baseline,所以使用其边框和 baseline 对齐,参见 mdn

For elements that do not have a baseline, the bottom margin edge is used instead.

给图片加上 vertical-align: text-bottom 即可解决

说了这么多,我选 flexbox 👍

process.argv 解析姿势

当执行类似 node foo.js bar/* 命令时,如果 bar/* 匹配文件路径时,实际得到的参数是:

bar/1
bar/2

不匹配文件路径时,得到的参数是

bar/*

让命令行丰富多彩

偶然看到 Node.js console.log 马上也要支持带颜色输出了,见 PR#19372。平时偶尔也折腾完命令行的文字颜色,但没深究过。今天就扒一扒如何让命令行丰富多彩:控制输出颜色

ANSI 转义控制码

wiki 是这么说明 ANSI escape code 的:

ANSI escape sequences are a standard for in-band signaling to control the cursor location, color, and other options on video text terminals.

简单说,就是控制命令行的光标、颜色。工作方式很简单,举例说明(Mac 环境下):

  • 输出文字颜色为蓝色: echo '\033[34m Gaara'
    image

  • 输出背景为蓝色:echo '\033[44m Gaara'
    image

上面的两条命令拆成两个部分:

  • 控制部分: \033[44m (CSI sequences - Control Sequence Introducer sequences)
  • 值部分:Gaara

控制部分可以拆开成三个小节:

  • 固定的开头ESC + [\033 是八进制的 ESC,也可以用 16 进制的 echo '\x1b[44m Gaara'
  • 结尾的控制类型,例如 m 是控制颜色的
  • 中间的参数值,44 表示背景色设为蓝色,34 表示前景色设为蓝色,详细的码表,可以见 wiki 中的 Color 部分

要同时设置前景色和背景色只需多个控制序列重复即可,例如 \x1b[44m\033[35m Gaara。以上只是简单的介绍了下如何利用 ANSI excape code 设置颜色。

Node.js 控制输出颜色

直接如下即可:

console.log('\033[33m info \033[0m')

回过头看 PR#19372,主要是新增了一个 util.formatWithOptions 方法:支持 color 配置选项,并将其传入 lib/util.js 内部的 inspect 方法,最终通过 stylizeWithColor 方法格式化颜色

node-ratelimiter 源码浅析

并发 bug

该库 2.1.3 版本,简化代码如下(没有考虑剩余的 duration,只是):

function get (fn) {
  var key = 'count'
  var max = 6
  var duration = 10000
  db.watch(key, function (err) {
    if (err) return fn(err)

    db.get(key, function (err, res) {
      if (err) return fn(err)

      if (!res) return create()

      decr(res)
    })
  })

  function decr (res) {
    var value = ~~res
    if (value <= 0) return fn(null, 0)
    db.multi()
      .set(key, value - 1)
      .exec(function (err, res) {
        if (err) return fn(err)

        return fn(null, value - 1)
      })
  }

  function create () {
    db.set(key, max, 'PX', duration, 'NX', function (err) {
      if (err) return fn(err)

      fn(null, max)
    })
  }
}

这个实现有个 bug (已被修复) 读写数据并不是原子操作,而是分成四步:watch() -> get() -> create()->set()。假设两个客户端同时 watch,并 get 读取了数据,一旦其中一个 set 成功,另一个便会 exec 失败( 注意:由于 watch 导致的 exec 撤销,不会抛出 err)。测试代码如下:

async.times(6, function (n, next) {
  get(next)
}, function (err, limits) {
  console.log(limits)
}) 

要修复的话,必须把 create、get、set 操作合并成原子操作:get+set 简化为 decr, createdecr 放入同一个事物

function get (fn) {
  var key = 'count'
  var max = 6
  var duration = 10000
  db.watch(key, function (err) {
    if (err) return fn(err)

    decr()
  })

  function decr (res) {
    db.multi()
      .set(key, max, 'PX', duration, 'NX')
      .decr(key)
      .exec(function (err, res) {
        var value = ~~res[1][1]
        if (err) return fn(err)

        return fn(null, value)
      })
  }
}

利用有序集简化 key

简化版代码,其实已经很精简了,但是该库需要能够支持剩余时间、不同的 max,所以使用了三个 key:count、limit、reset。该 pr 通过使用有续集,精简的 key 数量:

  • zcard 读取 count 值
  • 有续集里 key 按时间排序,用于计算剩余时间

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.