Giter Club home page Giter Club logo

er's Introduction

ER(Enterprise RIA) Framework

ER 是一个富浏览器端web应用的框架,适用于并能很方便地构建一个整站式的AJAX web应用。

ER具有如下特性:

  • 通过hash实现路径的管理,支持浏览器的前进和后退功能,以及URL的可访问性。
  • 提供精简、核心的Action、Model和View的抽象,使得构建RIA应用变得简单可行。
  • 提供可配置式的数据加载方案,提供灵活且完善的数据获取功能。
  • 提供支持基本逻辑和数据绑定的模板引擎,提供模板嵌套和母板页。
  • 不依赖任何第三方库,模块精简、可切分及独立运行。

ER总体结构

ER的目的在于让业务开发工程师可以关注于 数据(Model)业务(Action)视图(View) 这三部分,而不需要关心如 数据怎么获取权限如何管理URL如何控制 等技术性问题。

文档

cd {esui}
sudo gem install jsduck
jsduck —-config=jsduck/config.json
open doc/api/index.html

er's People

Contributors

chestnutchen avatar erik168 avatar justineo avatar killeryyl avatar leeight avatar otakustay avatar srhb18 avatar strwind 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  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

er's Issues

使用etpl作为模板

etpl完成后使用其作为模板引擎,自身不再提供模板功能,template模块仅作为etpl的桥接,保持向后兼容,等4.0去除template模块

关于Action的跳转处理

在项目中遇到了这样的情况
hash变化的自动Action跳转,在快速切换的状况下,之前的Action的Model加载处理之后,其界面变化会在新的Action中体现出来。

不知道这里是我没有正确的使用还是怎样。

此时实际上在Action的context中,path的已经与当前path不一致了,但是还是渲染出来了,如果新Action的数据加载在旧的之前完成了,那么干脆界面就变成旧的了。

当前我的处理是判断了一下context的path和当前path以及是否是主Action,如果不同,不继续处理。

请指教

Action的initBehavior事件疑问

按理说这个initBehavior就类似与以前er框架的render操作。在之后的refresh里是不会再次触发的了。这个在loadSubAction里很有必要这么做。我这里马上就弄好book-store里loadSubAction的样例了,期间遇到了些,一会请你一起看看。

函数即Action

现有的Action必须是一个对象,且需要实现enter方法。但在一些非常简单的环境中,逻辑并不需要固定的上下文以及太多的方法依赖。

因此希望Action可以直接使用一个函数,为此增加一个逻辑分支:

controller 对象加载Action得到一个对象,如果这个Action对象本身是一个函数,则直接调用之,调用时传递的参数与调用普通Action的enter方法的参数相同。

template需要延迟解析

存在这样的问题:

master.tpl

<!-- master: masterName -->
Hello <!-- contentplaceholder: name -->

user.tpl
<!-- target: user(master = masterName) -->
<!-- content: name-->
World

对应的js

define(
    function () {
        require('er/tpl!master.tpl');
        require('er/tpl!user.tpl');

        require('er/template').merge('user', container);
    }
);

基于esl的规则,2个模板文件会并行加载,谁先到谁后到不一定。但是当user模板加载后,会立刻根据其master等属性构造AST,此时如果master.tpluser.tpl晚到,会因没有master而导致user模板没有任何内容。

如果模板有合并是不会存在问题但,但开发环境的调试就很恶心。

一个解决方案是,模板在第一次使用的时候再解析为AST, @errorik 看看是否合适?

View不能很好的自定义container

原ER框架里有loadSubByPath,这里是可以自定义view的container的,也就是用view实现了局部刷新。现在的ER里的container全部都指向了config里的mainElement,仅能在url里添加container参数达到刷新指定DOM的效果。虽然也可以自己添加路由解决这个问题,但总感觉这里被做死了,请指教。

清理template的实现

现有template的实现是针对旧版ER而设计的,其中有不少的内容与新的框架和规范不符,比如:

  • xxx:lang的取值,新框架中不该存在类似这样的东西
  • 源码中去 module 中获取值的逻辑,新框架中也不应该存在,而且实现是通过win[xxx][variable]获取的,与现有的模块化开发相悖

因此,template的实现需要一次大的清理和调整,同时调整代码规范。

支持Action工厂

在产品线的部分模块(如报表功能)中,虽然不同Action面向的业务有所不同,但其数据源、逻辑、展现方式等都非常接近。

在这种情况下,假设使用传统的继承、组合式编程,虽然可以有效控制代码的质量,但依旧不可避免存在着不少重复的代码,并一定程度上对维护性有着负面的影响。

有部分产品线对这种功能的处理中,有产生一种方案,即由一个函数负责根据当前的上下文(业务模块、参数等)在运行时 生成一个Action 。在此,将这种方式中生成Action的函数称为 Action工厂

ER的任何版本中都没有对Action工厂作任何的支持,使得产品线需要使用一些较为繁杂的手段来实现这一功能(如使工厂作为一个Action,但其内部又有一套类似 controller 对象的逻辑)。

因此,希望新版ER可以对Action工厂进行实现,大致思路如下:

  1. controller 对象加载Action
  2. 如果Action拥有enter方法,则认为是普通的Action,按正常逻辑执行
  3. 如果Action没有enter方法,但有一个createRuntimeAction方法,则认为该对象是一个Action工厂,调用该方法,该方法会返回一个带有enter方法的对象作为最终的Action执行

这一方案中,依旧需要考虑几个点:

  • createRuntimeAction调用时传递的参数
  • createRuntimeAction是否允许返回一个 Promise 对象

Deferred对象触发回调时的this对象错误

Deferred对象进入 resolvedrejected 状态触发回调函数时,this应当是一个Promise对象,而现在的实现中,this是一个Deferred对象。不应该把Deferred对象直接暴露给回调函数,因为这时候额外调用resolvereject等函数有可能导致不预期的情况(比如未来修改为多次调用resolve会抛出错误)

需要修改 src/Deferred.jstryFlush函数,在调用call时传递deferred.promise()即可

增加子Action的全局跳转

现在在子Action中,通过点击<a>元素可以全局跳转,方法是使用<a data-redirect="global" href="...">...</a>这种形式

但是使用js代码无法全局跳转,必须使用locator.redirect来进行。这会导致Action在需要全局跳转时,不得不依赖locator组件,进一步造成可测性下降、解耦不足、Action复用性变小等结果。

因此给redirect增加一个参数:

// In action instance
this.redirect(url, { global: true });

来进行全局跳转

Controller: 子Action中a标签触发的跳转,点击后报错

Controller限定了一个逻辑:子Action中的所有a标签所触发的跳转只会使子Action跳转,而不会影响到主action。

实现是通过给子aciton的main元素绑定click事件监听,通过hijack方法判断事件是否a标签点击并会触发跳转。如果是一个跳转事件则使用闭包内redirect方法跳转子action.

问题:hijack方法在调用redirect方法时只传递了url参数,缺少必要参数options。

问题2:如果子action的a标签跳转需要使主action跳转(即改变locaiton.hash),如何处理?

关于template功能上的几个需求

今天讨论template的时候,提到有几个功能似乎现有的template实现没有提供,由于一直使用着最老版本的template,因此也没在意这些功能是否真实有用,在这里列一下:

  • for功能里加上index,变成<!-- for $list as $item, $index -->,比如表格的首行末行、奇偶行换色,会用到这功能。这个功能我认为还是实用的
  • 变量功能,比如经常出现的if判断,可以保留一个临时的变量值。这个功能我认为用户不大且实现麻烦。

完善各环节错误信息

各环节的错误信息经常被Deferred吞掉,需要收集起来再提供出去,进行一次全范围的排查

关于Model加载中出现错误的处理

@jinzhubaofu @errorrik

如沟通,我们现在在加载Model数据的阶段,没有错误处理,这已经造成了比较多的不便,因此我总结了一下这个事情,得到结论如下:

  • Model有数据源,数据源由很多个数据项组成,任何一个数据项都可能出错
  • Action只有一个Model,因此任何一个数据项出错,都应该认为是Model出错

所以原本我还在纠结这个错误处理在ModelAction哪一层做,结总结后发现这根本是2个维度的事:

  • Model的错误处理,针对单个数据项的错误进行处理
  • Action的错误处理,会收集Model的所有错误统一处理

因此我的设计如下:

  • Model.prototype.handleError,当任何一个数据项出错时,会把信息传递到这个方法,这个方法如果返回任何东西(包括不返回),表示错误已经处理完了直接吞掉这个错误就行。如果handleError抛出异常,则说明错误没处理完,这个错误需要上抛给Action
  • Action.prototype.handleError,当Model加载完,发现有一个或以上数据项出错时,把错误收集起来变成一个数组并调用这个方法。同样方法正常返回表示错误处理完,抛出异常表示错误没处理要继续上抛(就是eventsenteractionfail事件)

默认的2个handleError实现都是直接把收到的东西throw出去表示异常没处理完,这也是符合Promise模型的设计(当回调抛出异常时,表示进入 rejected 状态)。

两位看下这样搞能不能满足你们的需求,OK的话我会进行实现

尽量使用get接口而非属性

尽量将现有配置型的属性用get接口封装一下,以便实现更好的动态性,总结一下大概有:

  • View.template
  • View.container
  • Model.datasource
  • Action.viewType
  • Action.modelType

实现更好的Deferred错误模型

Promise的社区规范要求一个回调抛出异常时吞掉它并让Promise进入rejected状态,不过现实业务系统中很少有用异常进行状态迁移的,因此需要在这方面做一下扩展,比如让异常能够抛出来,或统一到events.notifyError上去

Controller: globalActionLoader的abort方法不存在

globalActionLoader是loadAction的返回值。

当loadAction成功找到了path对应的actionConfig时会返回一个带有abort方法的promise。

当loadAction无法找到actionConfig时,会返回一个已经被reject的promise,但这个promise不带有abort方法。这导致后续所有的Action都无法正确加载。

book-store购物车里的怪现象

来学新的er,在看demo时发现个怪事:假如在book-store的购物车里有9本书,在浏览器滚动条滚到最底部时会自动弹上去一些(chrome 版本 25.0.1364.152 m,屏幕最常见的1376*768全屏),结果就是看不到总价,也点不到清空购物车按钮。

是否需要暴露currentAction对象

原版的ER中,可以通过controller.currentAction获取 当前运行的主Action对象

但是从设计的原则上来说,Action应该是自治且封闭的,即一个Action对象中所有方法,都应该在内部完成,同时暴露一定的接口供交互使用。但不应该有任何的代码从一个全局的入口,通过currentAction来得到 当前运行的Action对象

当需要使用currentAction的时候,通常代表着程序在设计上存在着问题,应当有更合理的方式给予解决。

但是现阶段对需求的分析,并不能保证一定不需要这样的情况,因此提出这个话题,请大家讨论使用currentAction的场景,看看是否必须有该属性才能解决,话题有:

  1. 是否要有currentAction的暴露?
  2. 如果暴露currentAction,那么考虑到有子Action的存在,当前运行的Action对象可能不止一个,需要如何获取?是否需要有一个方法getRunningAction({Element} container)来获取与这个DOM元素挂钩的Action对象?

3.0.2 ajax问题

vimdiff了一下3.0.2与3.0.1的ajax实现,发现了这么一个差异:

// 3.0.2
ajax.hooks.serializeData = function(prefix, data) {}
// 3.0.1
ajax.hooks.serializeData = function(data) {}

ajax.request = function(options) {
    //....
    var query = ajax.hooks.serializeData(options.data, options.contentType, fakeXHR);
    //...
}

3.0.2版本中, prefix参数接收的options.data,data接收的options.contentType,导致ajax数据无法序列化,发送到后台的都是这样:

[object Object]: application/x-www-form-urlencoded

替换成3.0.1版本后,恢复正常!!!

是否由ER支持JSONP

众所周知,ER通常是和ESUI一起用的,这两个框架合作起来,形式如下:

  • ER控制hash变化的监听并传导至一个Action,实现一个基础框架
  • ESUI负责所有的视图功能,包括DOM的操纵
  • 另找一个库(由项目决定)来提供javascript语言层面的增强,如sugarjs或tangram、underscore等

在这个模式下,DOM由ESUI完成,语言本身由一个通用库完成,但唯独缺少一个应该算在DOM中但ESUI不提供,通用语言库也同样不提供的东西,就是 AJAX

同时,ER因为有数据加载的过程,因此本身也提供了一个精简的AJAX的实现。但是在这个规划下,JSONP和通过<img>元素发送LOG的功能并不在ER的范围内,这就会导致 项目需要额外实现这些功能,或找一个过于臃肿的库(如jQuery)来实现 ,这并不是整个ECOM体系下的项目想看到的结果。

因此,ER是否要提供JSONP成为一个值得考虑的问题。现有的ER已经额外提供了一个log函数用于通过<img>元素发送有去无回的日志记录,但是JSONP出于 实现复杂使用项目有限 的考虑,显得有些纠结。

因此,特开此讨论,是否需要由ER直接支持JSONP?

events和main模块是否合并

events 模块的唯一任务就是发出各种事件,现阶段只有一个error事件,未来可能有全局事件以方便做日志等工作,比如

  • enterAction
  • findAction
  • route

不过这个模块的任务似乎直接交给 main 模块就行,使用上require('er').on('error', handle);也很自然。

唯一的问题是,现在的 main 模块有一个start方法,依赖于 locatorroutercontroller 三个模块,这会形成循环依赖,在结构设计上不漂亮。同时作为入口的模块,依赖 Observable 模块在结构上也有些说不清。

如果在使用上没什么问题,建议不合并 eventsmain 模块,如果确实觉得合并有更大的收益,则考虑尽早合并。

请大家参与讨论

locator对象是否需要支持IE6

新版ER的希望是放弃对IE6的完美支持,其中非常重要的一点是 locator 对象将不再对IE6进行支持。

这一改动的直接后果是,使用新版ER构建的系统不再支持IE6的 前进、后退 功能,其它部分功能不受影响。

这一变动对IE6下访问系统存在一定影响,但 并不会导致功能的不可用

对于 locator 对象放弃IE6的考虑,是出于实现的复杂性以及其收益成本的。在IE6下,当hash发生变化时,并不会自动地产生一个历史记录项,而需要使用其它的手段来实现历史记录项的增加。一个基本的思路是创建一个<iframe>元素,通过改变该元素的文档内容,使IE6记录历史项。

对于这一方案,有2种实现方式:

  1. 每次hash发生变化时,加载一个远程的HTML页面,HTML页面中包含执行hash跳转相关的逻辑。
  2. 使用javascript创建一个<iframe>元素,并操纵其document来实现历史的记录。

第1种方案会在hash变化时加载远程的文件,造成额外的网络延迟和带宽损耗,并且增加了故障点,部分产品线确实出现过因该HTML文件加载中断而导致的系统不可用现象。该方案在经优化后可以使用缓存来减少网络请求,但不可避免至少需要有 2次 额外请求。

第2种方案可以去除网络请求,但是如果业务系统有修改过document.domain的值,则会失效,需要使用第1种方案进行后补。

基于以上的描述,综合考虑以下几点:

  • 为IE6做兼容的技术成本较大,无论从ER本身的实现上还是对业务系统的部署上都会产生额外的工作量
  • ER框架一直追求精简,希望以尽可能小的核心支持各产品线的开发
  • 已经有不少产品线开始放弃对IE6的支持
  • 该点问题并没有影响最终产品的可用性,仅仅是用户体验上有一定的降级

因此暂定放弃支持IE6。

如果有产品线需要对IE6有完美支持,还请提出,以方便进一步评估实现的成本与收益比

ajax模块需要全局配置

在很多系统中,对 XMLHttpRequest 在失败请问下有全局的处理,比如显示一个Popup来提示用户请求失败。

为了完成这一功能,ajax模块需要提供一个全局配置的接口,以支持全局的事件处理,可以有以下事件暴露出来:

  • done:请求成功
  • fail:请求失败

实现这一功能,可以让ajax模块对象支持Observable功能,以实现类似ajax.on('fail', handleGlobalError);形式的配置。

当一个 XMLHttpRequest 完成后, 先执行调用时绑定的处理函数,再执行全局的处理函数

梳理并实现全局事件

出于用户行为追踪和数据统计的需求,应该在框架层面有全局的生命周期型事件,这样就不需要一一修改Action.prototype.enter之类的来抓取并发送日志。

现在想得出来的事件有:

  • redirect:URL变化进行新的“页面”
  • route:router对象完成工作,找到对应的函数
  • forward:controller对象接收到指令开始工作
  • actionfound:找到了对应的Action配置
  • loadaction:开始加载action
  • actionloaded:action加载完毕
  • enteraction:进入action

是否有其它的需求,以及各事件给定的参数,供讨论。

ajax回调函数参数优化

现ajax模块在调用回调函数时,会传递2个参数:dataxhr,但传递2个参数使得多个ajax请求在做join操作时编码麻烦,参考以下代码:

var ajax = require('er/ajax');
var requests = [
    ajax.get('some/url'),
    ajax.get('another/url'),
    ajax.get('final/url')
];

function print(some, another, final) {
    // 注意这里的回调函数每个参数都是数组,
    // 必须每一个都取`[0]`才行,很麻烦
    console.log(some[0], another[0], final[0]);
}

// 等待3个ajax全部返回后执行
require('Deferred').join(requests).done(print);

额外的[0]取值显得 冗余 ,且 影响了代码的可读性

考虑到回调函数中的xhr参数,其实可以使用this访问得到,同时这个参数用得及少(偶尔会有responseXML之类的需求,但普通业务项目中使用非常少),因此应当使得ajax的回调函数尽可能地只有1个参数,因此设计如下:

  • 成功时回调,提供返回的数据(如果是 json 格式则进行parseJSON操作)
  • 失败时回调,提供状态码
  • 超时时回调,提供固定状态码 408 (Request Timeout)

针对此方案,需要修改 src/ajax.jsajax函数的部分实现,对调用resolvereject的地方的参数传递进行清理。

考虑到 #18 已经保证Deferred对象调用回调函数时传递其管理的Promise对象,且这个Promise对象无论通过promise()方法获取几次都是同一个对象,同时FakeXHR其实就是这个Promise对象再额外增加了几个方法,因此ajax调用回调函数时,this能够确切地指到这个FakeXHR对象且拥有如responseText之类的属性,不需要再做额外的修改。

本Issue打开3天供讨论,如无进一步结论,则按此方案修改。

Action有没有可能终止enter过程

比如:我在model load阶段,拿不到正常的数据。我在render的时候,肯定是会有错误的。

在modelloaded的时候,判断没有某项数据,这时候我期望停止这个过程(不进入render阶段),然后跳转到另外的页面,有没有办法呢?

如果我直接在modelloaded的时候redirect了,这时候可能会产生意想不到的结果(因为render还在做)。所以发了各issue问问。

内部处理起始路径

现在的ER当没有hash时,会自动进行一次重定向到config.indexURL里,这一次重定向会在历史记录中增加一帧,导致浏览器后退时回到没有hash的状态再次被跳回config.indexURL形成死循环

考虑内部处理掉这次跳转,即当hash不存在时,认为就是config.indexURL而不是跳转一次

er/ajax的request在post的时候有bug

参数不对。

看代码,对序列化数据的方法调用,参数存在问题。
看现象,data没post出去,反而post了%5Bobject%20Object%5D=application%2Fx-www-form-urlencoded

controller需要renderChildAction功能

在业务开发中,经常会使用一个Popup,随后将一个Action放在该Popup中,以完成跨模块的一些业务交互。

为了实现这一功能,controller对象需要一个renderChildAction功能,该方法的签名如下:

{Promise} renderChildAction({string} url, {string} container, {Object} params)

其中url为需要访问的路径,container为渲染该Action的DOM容器的id,params为直接传递给Action的参数。

方法返回一个 Promise 对象,当这个对象进入 resolved 状态时,会传递加载的Action作为参数。

以下内容需要作出改变:

  • 进入Action时的context参数中,需要有一个isChildAction的标记位。
  • container中的所有链接元素,如果改变hash,需要转换为renderChildAction进行,不可直接改变hash。
  • 其它修改hash的方法,如locator.redirect(url)可以不做处理,这需要Action在设计时有良好的掌握,以避免出现这类情况。

增加Deferred.when方法

有时候,一个函数根据情况,会选择性地返回Promise或普通对象,比如一个经典的带缓存的函数:

function getData(key) {
    if (cache[key]) {
        return cache[key];
    }
    else {
        return ajax.getJSON('/data/' + key)
            .then(addToCache);
    }
}

这种时候,调用它的代码就需要做额外的判断:

var data = getData(key);
if (Deferred.isPromise(data)) {
    data.then(next);
}
else {
    next(data);
}

这导致代码中有不少没啥意义的分支,因此希望有一个方法给统一起来:

var data = getData(key);
Deferred.when(data).then(next);

Deferred.when有以下表现:

  • 传入一个Promise时,直接返回该Promise对象
  • 传入非Promise时,返回一个已经在 resolved 状态的Promise,且这个PromisesyncModeEnabled开关为 true ,以便调试和单步

Action的事件不能很好的绑定

若在initBehavior里添加事件,会错过之前的enter,modelloaded等事件。
关键原因在继承Observable后,通过new Action这一步,并没有触发this._events = {};导致事件触发失效,除非在某处使用过一次on之后。
这个也导致自定义ActionType.prototype.onenter等等带on前缀的事件不能触发。

改进方案 在继承Observable的类里都添加个this._events = {};(此法不佳)
或者修改Observable 中fire方法里 前3行的位置到pool前面。(最好这样)

重新整理Deferred的API

趁正式版未定,将Deferred的API靠向when.js,弃用以前参考jQuery得出的API,以提供更为简洁、正确的接口,包括:

  • always改名为ensure,参考为什么always不合适
  • promise()方法改为promise属性,反正方法本来也只会返回固定对象
  • state()方法改为state属性
  • 添加resolver属性,提供 固定了this的resolvereject方法

关于增强组件的模块空间

当前的ER提供了最基础的功能,但还有不少增强性的组件可以提供,比如 #17 (comment) 提出的ObservableView,计划中还有一个TabView用来提供 一个区域内多个View相互切换 的抽象功能。

随着框架的发展,增强性的组件可以预见地会增多,而这些组件更多的是辅助业务开发使用,并不代表ER的核心功能,因此希望 有一个单独的文件夹来存放这些 ,因此希望讨论 该文件夹的命名 ,个人总结几个:

  • powered
  • enhanced
  • improved

当然也可以不用任何文件夹,直接放在 src/ 下,未来有10-20个增强组件的时候是否会导致ER的源码学习成本增加(找不到哪些才是重要的)

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.