Coder Social home page Coder Social logo

usernane / ajaxrequestjs Goto Github PK

View Code? Open in Web Editor NEW
5.0 3.0 0.0 186 KB

A JavaScript class library that can help in managing AJAX requests in simple way.

Home Page: https://ajaxrequestjs.org

License: MIT License

JavaScript 100.00%
ajax-request csrf javascript ajax web hacktoberfest

ajaxrequestjs's Introduction

AJAXRequest.js

A light weight JavaScript class library that can help in making AJAX requests much simpler task.

jsDelivr hits (GitHub)

Table of Content

Main features:

  • Assign multiple callbacks to execute before sending AJAX, on success, client error, server error, on disconnected or after AJAX is completed.
  • Get server response as a JSON, plain text or XML.
  • Enable and disable callbacks as needed based on conditions.
  • Adding custom headers to the request.
  • Automatic CSRF token extraction.

Installation

In order to use the library, you must first include the JavaScript file in your head tag of your web page. To have the latest v2.x.x release, include the following tag:

<head>
  <script src="https://cdn.jsdelivr.net/gh/usernane/[email protected]/AJAXRequest.js"></script>
</head>

It is possible to use the minified version of the libray by including the following JavaScript:

<head>
  <script src="https://cdn.jsdelivr.net/gh/usernane/[email protected]/AJAXRequest.min.js"></script>
</head>

Basic Usage

The following code sample shows the most basic usage of the library.

// Use the global instance 'ajax'. Another option is to create new instance of the class [`AJAXRequest`](https://github.com/usernane/AJAXRequestJs/blob/master/AJAXRequest.js)
ajax.setMethod('get');

//The URL that will receive the request.
ajax.setURL('https://api.github.com/repos/usernane/AJAXRequestJs');

//enable verbose mode for development to get more informative messages in the console
ajax.verbos = true;

//Adds one callback to execute on success. We can add more.
ajax.setOnSuccess(function(){
    //The response might be stored as JSON object
    if(this.jsonResponse){
        console.log(this.jsonResponse);
    } else {
        //Or, it can be plain
        console.log(this.response);
    }
});
    
ajax.send();

Configuration

When creating an instance of the class AJAXRequest, there are configuration options which are optional. They can be used to initialize the attributes of the instance.

{
    /**
     * The base URL that will receive the request.
     */
    base:string,
    
    /**
     * The URL that will receive the request or the path part of the URL if base is set.
     */
    url:string,
    
    /**
     * Request method. If not provided, 'GET' is used.
     */
    method:string,
    
    /**
     * Parameters which will be send with the request. It can be an object, a 
     * `FormData` object or string in the form `key1=value1&key2=value2`.
     */
    params:object|string|FormData,
    
    /**
     * A boolean which is used to enable or disable AJAX.
     */
    enabled:true,
    
    /**
     * If this one is set to true, more informative messages will appear in the console.
     */
    verbose:boolean,
    
    /**
     * Extra headers to send with the request.
     */
    headers:{},
    
    /**
     * A set of callbacks. The enabled ones will be executed before AJAX request is sent.
     * The developer can use them to collect user inputs or intrupt AJAX request and disable it before 
     * Sending it to server.
     */
    beforeAjax:array|function, 
    
    /**
     * A set of callbacks. The enabled ones executed when the request is finished with status code 2xx or 3xx.
     */
    onSuccess:array|function, 
    
    /**
     * A set of callbacks. The enabled ones executed when the request is finished with status code 4xx.
     */
    onClientErr:array|function, 
    
    /**
     * A set of callbacks. The enabled ones executed when the request is finished with status code 5xx.
     */
    onServerErr:array|function, 
    
    /**
     * A set of callbacks. The enabled ones executed when there is no interned connection.
     */
    onDisconnected:array|function, 
    
    /**
     * A set of callbacks. The enabled ones executed when the request is finished without 
     * looking at the status of the response.
     */
    afterAjax:array|function, 
    
    /**
     * A set of callbacks. The enabled ones executed when an exception is thrown by 
     * any callback in the 'beforeAjax', 'afterAjax', 'onSuccess', 'onClientErr',
     * 'onServerErr' and 'onDisconnected'.
     */
    onErr:array|function,
}

Properties Accessable in Callbacks

Inside the callback that will be executed, developer will have access to the properties of AJAX request and its response. The developer can use the keyword this to access them. The available properties are as follows:

function () {
    
    //The instance of the class. Can be used to modify the attributes of the object within the callback.
    this.AJAXRequest;
    
    //Response status code such as 200 or 404.
    this.status;
    
    //Server response as string.
    this.response;
    
    //If the server sent the response as JSON, this attribute is set to JSON object. 
    //If not sent as JSON, it will be set to null.
    this.jsonResponse;
    
    //If the server sent the response as XML, this one will be set to a 
    //string that represents the received xml tree.
    this.xmlResponse
    
    //An object that contains response headers. The keys of the object are headers 
    //names and the values are headers values.
    this.responseHeaders;
    
    //An object that holds binded object information.
    this.props
}

Note that for the callbacks which are set to be executed before the AJAX request is sent to the server only the property this.AJAXRequest is available. The other ones will be undefined. For the onErr callbacks, there is additional property which has the name e that represents the thrown Error and can be accessed in same manner.

Types of Callbacks

One of the features of the library is the ability to set functions to execute in specific cases. In this section, we explain the available callbacks and how to use them.

Before AJAX

Usually, before sending AJAX request to the server, checking for user inputs validation happens in this callback. A callback of this type can be set using the method AJAXRequest.setBeforeAjax(). Also, it can be part of the configuration that is used to initialize the AJAXRequest instance. This type of callback works as an interceptor.

ajax.setMethod('get');
ajax.setBase('https://api.github.com/repo');
ajax.setURL('url:'usernane/AJAXRequestJs');

//A call back can be added as an object or a function.
//Add as an object for customizing options.
ajax.setBeforeAjax({
  id:'Update Name',
  callback:function(){
       // Collect user inputs, validate them, etc...
       var firstName = document.getElementById('name-input').value.trim();
       if (firstName.length === 0) {
           this.AJAXRequest.setEnabled(false);
           console.log('Missing name.');
       } else {
           this.AJAXRequest.setEnabled(true);
       }
       this.AJAXRequest.setParams({
           name:firstName
       });
   }
});

//Note that the callback will not override the existing one.
//It will be added beside the existng one.
var id = ajax.setBeforeAjax(function() {
    // Do something else
});

After AJAX

This type of callback will be executed after AJAX response is received. It will get executed regradless of response code of the server. This acts like the finally in a try-catch statement. If the developer would like to handle server response in case of error and success, he can use this callback.

//Creating new instance instead of using global 'ajax' constant.
var ajaxObj = new AJAXRequest({
    method:'get',
    base:'https://api.github.com/repos',
    url:'usernane/AJAXRequestJs',
    
    afterAjax:function(){
         console.log('Status code: '+this.status);
         if (this.status < 400) {
             console.log('No Errors');
         } else if (this.status >= 400) {
             console.error('Error')
         }
     }
});

var id = ajaxObj.setAfterAjax(function() {
    // Do something else
});

On Success

The on success callback is executed when the server sends a 2xx or 3xx response code.

var ajaxObj = new AJAXRequest({
    method:'get',
    url:'https://api.github.com/repos/usernane/AJAXRequestJs',
    
    onSuccess:function(){
         console.log('Status code: '+this.status);
         if (this.jsonResponse !== null) {
             console.log('Received server response as JSON.');
             console.log(this.jsonResponse);
         } else if (this.xmlResponse !== null) {
             console.log('Received server response as XML.');
             console.log(this.xmlResponse);
         } else {
             console.log('Received server response as plain text.');
             console.log(this.response);
         }
     }
});

var id = ajaxObj.setOnSuccess(function() {
    // Do something else
});

On Client Error

The on client callback is executed when the server sends a 4xx response code.

var ajaxObj = new AJAXRequest({
    method:'get',
    url:'https://api.github.com/repos/usernane/AJAXRequestJs',
    
    onClientErr:function(){
         console.log('Status code: '+this.status);
         if (this.jsonResponse !== null) {
             console.log('Received server response as JSON.');
             console.log(this.jsonResponse);
         } else if (this.xmlResponse !== null) {
             console.log('Received server response as XML.');
             console.log(this.xmlResponse);
         } else {
             console.log('Received server response as plain text.');
             console.log(this.response);
         }
     }
});

var id = ajax.setOnClientError(function() {
    // Do something else
});

On Server Error

The on server error callback is executed when the server sends a 5xx response code.

var ajaxObj = new AJAXRequest({
    method:'get',
    url:'https://api.github.com/repos/usernane/AJAXRequestJs',
    
    onServerErr:[
        function(){
            console.log('Status code: '+this.status);
            if (this.jsonResponse !== null) {
                console.log('Received server response as JSON.');
                console.log(this.jsonResponse);
            } else if (this.xmlResponse !== null) {
                console.log('Received server response as XML.');
                console.log(this.xmlResponse);
            } else {
                console.log('Received server response as plain text.');
                console.log(this.response);
            }
        }
    ]
});

var id = ajaxObj.setOnServerError(function() {
    // Do something else
});

On Disconnected

The on disconnected callback is executed when the class detects that there is no internet connection is available.

var ajaxObj = new AJAXRequest({
    method:'get',
    url:'https://api.github.com/repos/usernane/AJAXRequestJs',
    
    onDisconnected:[
        function(){
            console.log('Status code: '+this.status);
            console.error('No internet connection! Make sure that you are connected to the internet.');
        }
    ]
});

var id = ajaxObj.setOnDisconnected(function() {
    // Do something else
});

On Error

This type of callback will be executed only when an exception is thrown by any callback which is included in the beforeAjax, afterAjax, onSuccess, onClientErr, onServerErr or onDisconnected. Think of it as the catch block of the AJAX request.

var ajaxObj = new AJAXRequest({
    method:'get',
    url:'https://api.github.com/repos/usernane/AJAXRequestJs',
    
    onErr:function(){
         console.log('An error in the code');
         console.log(this.e);
     }
});

var id = ajaxObj.setOnError(function() {
    // Do something else
});

Sending Parameters to Server

The class does support sending data using GET, POST, or DELETE request methods. The data can be a simple string, an object or a DataForm object.

As a String

The following sample code shows how to send parameters to the server as an object. We use packagist.org public API in this example.

 var ajax = new AJAXRequest({
    method:'get',
    url:'https://packagist.org/packages/list.json',
    params:'vendor=webfiori',
    onSuccess: [
        function(){
            if (this.jsonResponse) {
                // We must know the format of JSON object to get data.
                for(var x = 0 ; x < this.jsonResponse.packageNames.length ; x++) {
                    console.log('Package #'+x+' Name: '+this.jsonResponse.packageNames[x]);
                }
            } else {
              console.warn('No JSON data was received.');
            }
        }
    ]
}).send();

As an Object

The following sample code shows how to send parameters to the server as a JavaScript object. This time, we are using the methods of the class AJAXRequest instead of using the configuration object.

 var ajaxObj = new AJAXRequest({
    method:'get',
    url:'https://packagist.org/search.json'
});

// Adds a custom parameter.
var searchString = 'webfiori';
var seachObj = {
    q:searchString
};
ajaxObj.setParams(seachObj);
ajaxObj.setOnSuccess(function(){
    if (this.jsonResponse) {
        console.warn('Printing Search Results:');
        for(var x = 0 ; x < this.jsonResponse.results.length ; x++) {
            var searchResult = this.jsonResponse.results[x];
            console.warn('Result #'+x+' Info:');
            console.log('Package Name: '+searchResult.name);
            console.log('Description: '+searchResult.description);
            console.log('Link: '+searchResult.url);
            console.log('Total Downloads: '+searchResult.downloads);
        }
    } else {
        console.warn('No JSON data was received.');
    }
});
ajaxObj.send();

As a FormData Object

FormData is usually used to send data to the server using POST or PUT to modify something in the database. Also, it can be used to upload files to the server. Simply, we create the object FormData, add the attributes and use the method AJAXRequest.setParams(). This time, we collect user input on a callback which is executed before sending the request. Let's assume that we have the following HTML code.

<div id="search-form">
  <label for="search-input">Type in Search Term:</label>
  <input type="text" name="search-term">
  
  //Notice how we call the 'send' method.
  <input type="submit" onclick="window.ajax.send()">
</div>
<div id="search-result-display">
    <!--search results will appear here-->
</div>

The following JavasScript code can be used to handel the search action.

var ajaxObj = new AJAXRequest({
    url:'https://example.com/search',
    beforeAjax:[
        function () {
            var searchTerm = document.getElementById('search-term-input').value;
            var form = new FormData();
            form.append('search-term',searchTerm);
            
            //We set the parameters inside the callback.
            this.AJAXRequest.setParams(form);
            
            document.getElementById('search-result-display').innerHTML = 'Searching for "'+searchTerm+'"....';
        }
    ],
    onSuccess: [
        function () {
            document.getElementById('search-result-display').innerHTML = this.response;
        }
    ]
});

Adding Custom Headers

It is possible to add custom headers to the request in two ways. One way is to use the configuration variable headers and the second one is to use the method AJAXRequest.addHeader(). The following example shows how to add headers using first way.

var ajaxObj = new AJAXRequest({
    url:'https://example.com/api',
    method:'post',
    headers:{
        //The request will be sent with two additional headers.
        'custom-header-1':'Header value',
        'token':'Some token'
    },
    onSuccess:[
        function () {
            //...
        }
    ]
}).send();

The next example shows how to use second way.

var ajaxObj = new AJAXRequest({
    url:'https://example.com/api',
    method:'post',
    onSuccess:[
        function () {
            //...
        }
    ]
});
ajaxObj.addHeader('custom-header-1','Header value');
ajaxObj.addHeader('token','Some token');
ajaxObj.send();

CSRF Token

The library can extract CSRF token from the DOM and send it with request headers automatically. In order for this to happen, the token must be stored somewhere. There are 3 ways at which the token can be kept in the client side:

  • As a meta tag with name="csrf-token and content="the_token".
  • As an input element with name="csrf-token and value="the_token".
  • As a window.csrfToken variable. If one of the 3 is met, the token will be sent to the server in the headers. The name of the header will be X-CSRF-TOKEN. Note that the token must be created and set by the server. Also, note that it will be only sent with unsafe request methods (PUT,POST and DELETE).

Customizing Callback Options

When adding new callback, it can be added as a function or as an object. The later way can be used to customize callback options and how it behave. When adding a callback as an object, the object can have following properties:

{
 //An ID for the callback.
 id:'My Callback',
 
 //A boolean or a function that evaluate to true. Used to decide if the callback will be executed or not.
 call:true,
 
 //An optional object that holds properties at which they can be accessed withen the callback
 props:{}
 
 //The callback function
 callback:function
}

Custom ID

The ID is used to distinguish callbacks from each other in one pool. This means it is not possible to have two callbacks with same IDs set for a case such as on-success. The property that is used to set custom ID has the name id.

// This is not allowed. The second callback will not be added since one with same ID was added.
ajax.setOnSuccess({
 id:'Update User',
 callback:function () {
  //...
 }
});
ajax.setOnSuccess({
 id:'Update User',
 callback:function () {
  //...
 }
});

On the other hand, it is possible to have two callbacks in two pools with same ID. This can help in grouping callbacks in different pools and enable or disable them using one ID.

// This is allowed.

ajax.setOnSuccess({
 id:'Update User',
 callback:function () {
  //...
 }
});
ajax.setOnClientError({
 id:'Update User',
 callback:function () {
  //...
 }
});
ajax.setOnServerError({
 id:'Update User',
 callback:function () {
  //...
 }
});

// Now can enable or disable them in one batch
ajax.setCallsEnabled('Update User', false);

Enabling or Disabling

One feature that the developer can use is the ability to disable or enable callback based on function expression. If the function evaluate to true, then the callback will be executed. Other than that, it will be skipped.

The property that is used to set if the callback is enabled or disabled has the name call.

ajax.setOnServerError({
 id:'Update User',
 call:function() {
  if (this.status === 505) {
   return true;
  }
  return false;
 },
 callback:function () {
  //...
 }
});

Binding Properties

The developer might want to access properties which are not in the scope of the function. One way to do it is to have global variables. Another way which is the recomended way is to bind the variables with properties while adding the callback and later access them.

var obj = {username:'Ibrahim'};

ajax.setOnServerError({
 id:'Update User',
 props: obj
 callback:function () {
 //Will print the value of 'obj.username' which is 'Ibrahim'.
  console.log(this.props.username);
 }

If the value of the property is changed inside the callback, it will be also changed in the referenced objec.

Another way to bind an object to multiple callbacks is to use the method AJAXRequest.bind(). The method can be used to bind an object to multipe callbacks in multiple pools or to specific callback in specific pool.

var o1 = {
 name:'Hassan'
};
//Bind with all callbacks
ajax.bind(o1);

//Bind with any callback with ID = 'AJAX Success' on all pools.
ajax.bind(o1, 'AJAX Success');

//Bind with all callbacks on the pool 'success'.
ajax.bind(o1, null, 'success');

//Bind with all callback with ID = 'AJAX Success' on the pool 'success'.
ajax.bind(o1, 'AJAX Success', 'success');

Retry

One of the features of the library is to have it retry to send AJAX request in case there was no internet connection. The developer can use the method AJAXRequest.setRetry() to specify retry attributes. The method has 4 parameters, times, timeBetweenEachTryInSeconds, func and , props. The parameter times represents how many times to attempt AJAX request before stopping. The parameter timeBetweenEachTryInSeconds represents number of seconds to wait before attemting to send the request again. The func is a callback to execute in case of retry event. The last parameter is an object that holds extra parameters to pass to the callback.

The callback will have two parameters, first one is number of seconds remaining before retrying and, second one is pass number (current retry attempt number).

The following code sample shows basic use case for this functionality.

ajax.setRetry(4, 14, function (remainingSec, passNum) {
  console.log('Pass number: '+passNum);
  console.log('Retry after '+remainingSec);
});

Verbose Mode

Verbose mode is used in development. It shows more informative messages in the console regarding the execution. To enable or disable verbose mode, the developer must change the value of the property verbose of the instance as follows:

// Enabled
ajax.verbose = true;

// Disabled
ajax.verbose = false;

API Reference

If you would like to read the API reference of the library, please check here.

Usage Examples

If you are looking for example on how to use the library, please check here.

License

The project is licensed under MIT license.

ajaxrequestjs's People

Contributors

ibrahimbeladi avatar usernane avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ajaxrequestjs's Issues

[Feature Request] Support for Retry on Disconnected

Currently, the library will execute the ondisconnected callbacks without retrying to connect. One feature that would be great is to have the ability to retry running AJAX request a number of specific times before falling back to ondisconnected. This can be supplied as an option that can be set on the instance using a method:

AJAXRequest.setRetry(times, timeBetweenEachTryInSeconds, func)

Where times is a positive number that specify the number of times to retry sending AJAX request before falling back to ondisconnected, timeBetweenEachTryInSeconds is number of seconds between each run, and func is an optional function to execute before each try.

Add Support for Enabling and Disabling Callback Based on Function Expression

The library currently supports disabling and enabling callbacks based on boolean value which is set by the method AJAXRequest.setCallEnabled(). One downside of this approach is that it increases the chances of bugs if there are many callbacks and the developer have to switch between callbacks based on application criteria.

One solution to this problem is to bind the process of enabling and disabling a callback to a function expression. Instead of making the method AJAXRequest.setCallEnabled() only accepts a boolean, make it accepts a function that if it returns true, the callback will be executed.

Add Support for Binding Custom Properties on Callbacks

One noted feature of the library is the ability to access properties within a call back such as this.jsonResponse or this.status. One suggestion is to have the ability to bind custom attributes to the callback. This will allow the developer to access properties of a specific variable without having to declare a global variable.

[Bug] Multiple AJAX Requests Using Same Instance Result in an Error

One of the things that the library supports is the use of the global ajax instance. This helps in having one location where a developer define all of his AJAX calls.

It was noted that if two calls are issued back to back, the second call will always fail. In Firefox, it is shown as follows when viewed in the network tab:
image

[Feature Request] Add Support for Binding Props Using Single Method

Suppose that a developer want to bind a property that will be used by all callbacks which exist in AJAXRequest instance. Currently, the only why to bind them is by looping throgh all existing callbacks using thier IDs in addition to all pools. The code that the developer will have to write is lengthy.

A suggested solution for this problem is to have a method with following signature:
AJAXRequest.bind(name, varToBind [,callbackId [, poolName]])

The method should accept two parameters at least, the first parameter is the name that will be used to access the property and the second one is the value that will be linked. An optional parameter could be a callback ID. So that the binding will only be for the callback with the given ID. A fourth optional parameter could be pool name. So that the variable will be only linked with callbacks in the specified pool.

Associated Tasks:

[Feature Request] Support for Silent Mode

It is noted that the library shows informative messages in the console even if verbose mode is turned off. The messages only shows status of AJAX request and simple warnings.

One feature that would be great to have is silent mode. In this mode, the library should not show any messages in the console except for errors.

Can't use serialized array as params

Hi,
i love your library. Before i found this i wrote all my ajax calls in raw jquery ajax. That worked well but is much code. Now i try to change to your library. That's very easy and fast. But i have a big problem.

In most of my ajax calls, i catch the form data with:
$("#formid-name").serializeArray();

With raw jquery ajax that worked well. jquery sets the header
content-type: application/x-www-form-urlencoded; charset=UTF-8

I tried to build that with your library but it fails. This is the payload with an ajax request with your library.
image

You library tries to change my serialized object to convert it as FormData object.

AJAXRequestJs/AJAXRequest.js

Lines 1427 to 1434 in fd64840

if (typeof this.params === 'object' && this.params.toString() !== '[object FormData]') {
this.log('AJAXRequest.send: An object is given. Extracting values...', 'info');
if (method === 'PUT' || method === 'POST') {
this.log('AJAXRequest.send: Will store parameters in FormData since request method is ' + method + '.', 'info');
var localParams = new FormData();
} else {
var localParams = '';
}

image

How can i pass an jquery serialized array?
Can you help me?

Kind regards

[Bug] Request URL Become Invalid When URL is Set with Base

Suppose that the base is set to https://example.com/ and request URL is set to https://https://example.com/apis/add-user. In this case, the library will send a request to https://example.com//https://https://example.com/apis/add-user which is incorrect. The expected behavior is that the library should send a request to https://https://example.com/apis/add-user.

[Feature Request] Add Support for Checking if There is an Active XHR Request

Suppose that a web page is sending multiple AJAX requests to servers to load items and there is one common onsuccess callback that will be executed which stops loading indicator of the page. Currently, the callback will be executed whenever one of AJAX requests is finished. This will stop loading indicator of the page even though the set of requests is not finished yet.

To solve this issue, we could have a method to check if there is an active XHR request or not. A sample use case for such method would be like this:

ajax.setAfterAjax({
    id:'Common Callback',
    call:true,
    callback:function () {
        if (!this.AJAXRequest.hasActiveRequest()) {
            this.props.loading = false;
        }
    }
});

Finally

Make a new hook (function/method/closure) for executing after the ajax request has finally finished. Which executes regardless of the state. Just like try-catch-finally.

[Bug] Overlapping Response

It is noticed that when sending two AJAX requests at the same time, the response of the two may overlap. This is caused by a race condition.

[Feature Request] Add Support for Setting a Base URL

In many cases, AJAX Request is usually sent to same server which having one base URL but the request is usually go to different end point. Currently, the developer have to set the base URL for every AJAX call. Instead, it is better to have the instance uses one base URL for all requests.

The base should be set in two ways, eather extracted from the base tag of the page or set manually using a method such as AJAXRequest.setBase

Support for Keyed IDs For Callbacks Instead of Numbers

When adding a callback, the library assigns an ID to the callback. Currently, the ID is actually the number of callback in callbacks queue. One bad thing noted about this is that the developer does not actually know what the callback is for. This also makes it difficult for the developer on deciding which callback to disable and enable.

One suggestion to overcome this issue is to allow the developer to use keyed IDs. Instead of making the library gives a number as callback ID, allow the developer to give a name for the callback as an ID.

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.