Giter Club home page Giter Club logo

didact's Introduction

Didact

A DIY guide to build your own React

This repository goes together with a series of posts that explains how to build React from scratch step by step. You can jump straight to the last post which is self-contained and includes everything.

Blog Post Code sample Commits Other languages
Introduction
Rendering DOM elements codepen diff 中文
Element creation and JSX codepen diff 中文
Virtual DOM and reconciliation codepen diff diff diff 中文
Components and State codepen diff 中文
Fiber: Incremental reconciliation (self-contained post) codepen diff diff 中文
The one with Hooks (self-contained post) codesandbox 中文

Follow @pomber on twitter for updates.

License

The MIT License (MIT)

didact's People

Contributors

chinanf-boy avatar pomber avatar ppeeou avatar tangdingga1 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  avatar  avatar  avatar  avatar

didact's Issues

Adding useEffect hook

  1. add global variable
let pendingEffects = []
  1. cerate a hook and add effects tag
function useEffect(fn, deps) {
            const hook = {
                tag: "EFFECT",
                fn,
                deps,
            }

            wipFiber._hooks.push(hook)
            hookIndex++
}
  1. modify performUnitOfWork function
if (isFunctionComponent) {
...
Object .keys(wipFiber._hooks)
                    .filter(hookIndex => wipFiber._hooks[hookIndex].tag === "EFFECT")
                    .forEach(hookIndex => {
                        const oldHook =
                            wipFiber.alternate &&
                            wipFiber.alternate._hooks &&
                            wipFiber.alternate._hooks[hookIndex]

                        const hook = wipFiber._hooks[hookIndex]
                        const depsChanged = (prev, next) => (_, index) => prev[index] !== next[index];
                        if (hook.deps.length === 0 && !oldHook
                            || oldHook && (oldHook.deps.length !== hook.deps.length
                                || oldHook && hook.deps.filter(depsChanged(oldHook.deps, hook.deps)).length !== 0)) {
                            pendingEffects.push(hook.fn)
                        }
                    })
...
  1. go to commitRoot function
...
pendingEffects.forEach(it => it()) // call pending effects after render

help: Confused with 'requestIdleCallback(workLoop)'

In Step III: Concurrent Mode, I learn that: requestIdleCallback(func) will call the call back function when the browser is idle.
But in workLoop function, that while loop confused me.

function workLoop(deadline) {
  let shouldYield = false
  while (nextUnitOfWork && !shouldYield) {
    nextUnitOfWork = performUnitOfWork(
      nextUnitOfWork
    )
    shouldYield = deadline.timeRemaining() < 1
  }
  requestIdleCallback(workLoop)
}

My question is: if shoudYield is false, it means that the browser is busy, so we should stop calling the next unit of work.
But in this while loop, if shoudYield is false, the loop will continue and do the next unit of work. Why?

flatten children

sometimes children can be arrays:

<div>
{posts.map(post => <p>{post}</p>)}
</div>

this causes problems for didact.

the solution is to just flatten children:

 reconcileChildren(fiber, fiber.props.children.flat())

Duplicate deletion commit

Thanks for your blog and code sharing, Didact is awesome!

I got an issue here when I tried to delete several siblings in the same time.

didact/didact.js

Lines 124 to 129 in a127ff4

} else if (fiber.effectTag === "DELETION") {
commitDeletion(fiber, domParent)
}
commitWork(fiber.child)
commitWork(fiber.sibling)

In this line, after one fiber gets deleted, its sibling will commitWork next, which has been already registered in deletions.

As a result, some fiber will be deleted more than once (after its sibling and in deletions.forEach), which will cause an error.

Setting value in useState hooks

I just followed the whole (new) tutorial on here https://pomb.us/build-your-own-react/ and I have to start off by saying amazing job. Super detailed explanations and the animations and display is obviously beautiful and stunning.

I have a question, though. Although most of the entire post is extremely in-depth, I felt that the useState section was a little terse and I'm currently left unsure of how to utilize the setState function.

Logically, it just doesn't quite make sense to me how to implement the setState function given that each hook action is executed as action(hook.state). This would only be executing a function (function required) on the current state value. But I'm failing to see where the implementation would be of updating the current state.

That being said, another part where I felt was left out of this is calling render again to update the state. I had noticed it was in one of the codesandbox examples but it doesn't seem to appear in the example code itself. Obviously this isn't a full react implementation so i wouldn't expect it to just "work" so it seems like the solution here is to include the render function in any other function that would require a state update. My guess is that this would eventually just be tied into the overall state of the application and that would trigger a rerender.

Thanks for the guide and I look forward to any response

Doesn't render elements on different containers.

Didact.render(element1, container1);
Didact.render(element2, container2);

Expected Behaviour:
element1 should have been appended to the container1 and element2 should have been appended to the container2.

Current Behaviour:
Only element2 is being appended to container2.

Reason:
The second render call is executed before workLoop is executed for the first time as a result wipRoot and nextUnitOfWork change before the first render call gets the chance to render element1, container1.

Possible Fix:

  1. Instead of assigning wipRoot in the render function, we maintain a queue of wipRoot.
  2. In workLoop we check if there is no nextUnitOfwork and wipQueue is not empty then we pop the first element assign it to wipRoot and set the nextUnitOfWork.
let wipQueue = [];
function render(element, container) {
  let tWipRoot;
  tWipRoot = {
    dom: container,
    props: {
      children: [element],
    },
    alternate: currentRoot,
  };
  deletions = [];
 wipQueue.push(tWipRoot);
}

function workLoop(deadline) {
  let shouldYield = false;

  if (!nextUnitOfWork && wipQueue) {
    wipRoot = wipQueue.shift();
    nextUnitOfWork = wipRoot;
  }

  while (nextUnitOfWork && !shouldYield) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    shouldYield = deadline.timeRemaining() < 1;
  }

  if (!nextUnitOfWork && wipRoot) {
    commitRoot();
  }

Although this solution works, we also have to maintain another list of currentRoot for hooks to work.
Also, I am new to JS and front-end in general. So there might be a better solution, Just wanted to share my thoughts.

useState + setTimeout = broken state setter

const SubTest = () => {
    const [s, setS] = useState(10);
    setTimeout(() => {
        const newValue = Math.random();
        console.log('----', newValue)
        setS(s => newValue);
    }, 1000);
    return (
        <h3> Count: {s} </h3>
    );
}

const Test = (): JSX.Element => {
    const [s, setS] = useState(10);

    setTimeout(() => {
        const newValue = Math.random();
        console.log(newValue)
        setS(s => newValue);
    }, 2000);

    return (
        <div>
            <h1>
                Count: {s} {s1}
            </h1>
            <SubTest />
            <SubTest />
        </div>
    );
}

// ---------------------

const MainCmp = (props: any) => {
    return (
        <div>{Test()}</div>
    );
}

const element = <MainCmp />;
const container = document.getElementById("root")
render(element, container!)

and the result is:
image

  • Main (broken): the setter in Test component not change the state value (s, it is always 10), refresh the component but the value remain the initial.

  • Secondary (sometimes broken after 1st change): counter in SubTest sometimes work, sometimes break after first value change.

no console error, the newValue is correct, component is rerun each time just the state saving issue

somehow always a new hook created which not conneted with the dom and never deleted the old one so at end browser with freeze after 15-30 sec

Reconciliation is too naive

Hey there, I really appreciate your tutorial, great stuff.

That said, the way you handle reconciliation leads to bugs if things are conditionally rendered. I've forked your codesandbox to show the issue: https://codesandbox.io/s/didact-8-0l4lz. You should see that clicking the show / hide button will duplicate the count element. Note that if you first increment the count it works correctly, it's not obvious to me why that is.

Cheers!

useState not work in multiple case (with setTimeout)

@pomber

1. Issue with setTimeout

const element = <Test />
const container = document.getElementById("root")
render(element, container)
const Test = (): JSX.Element => {
    document.title = `Home Page`;

    const [s, setS] = useState(10);

    setTimeout(() => {
        setS(Math.random());   // result is error in this moment
    }, 5000);

    return (
        <div>
            <h1 onClick={() => setS(c => c + 1)}>
                Count: {s}
            </h1>
        </div>
    );
}
export function useState(initial) {
    ...........
    actions.forEach(action => hook.state = action(hook.state)); // here the action is a number and not the function which should set the value
    // TypeError: action is not a function 
    ........

2. Issue with setTimeout

same code just with directly called element

const element = Test();
const container = document.getElementById("root")
render(element, container)
export function useState(initial) {
    // wipFiber is     ##@@null
    const oldHook = wipFiber.alternate && wipFiber.alternate.hooks && wipFiber.alternate.hooks[hookIndex];

use state not work if i call it from set timeout / interval

"DELETION" exception

In commitWork function, when entering DELETION condition judgment,it should ruturn

    )
  } else if (fiber.effectTag === "DELETION") {
    domParent.removeChild(fiber.dom)
+   return
  }

  commitWork(fiber.child)
  commitWork(fiber.sibling)
}

Otherwise didact will repeatedly delete child elements, and will throw a exception:

屏幕快照 2020-10-28 下午8 18 40

Here is my test code

/** @jsx Didact.createElement */
const container = document.getElementById("root")

const updateValue = e => {
  rerender(e.target.value)
}

const rerender = value => {
  const element = (
    <div>
      <input onInput={updateValue} value={value} />
      <h2>Hello {value}</h2>
      {
        value === '1' ? <div><span>a</span><span>b</span></div> : <div><div>c</div><div>d</div></div>
      }
    </div>
  )
  Didact.render(element, container)
}

rerender("World")

The operation effect is as follows:

ezgif com-gif-maker (1)

Test it on codesandbox

I open a PR to fix the question

Old Fiber For First Render Is Null !!?

i check this code and i think we need to set condition for when old Fiber is null this mean we are in first render!

oldFiber != null

let currentRoot = null

alternate: currentRoot,

Solution

we just rewrite a reconciler function

const reconcileChildren = (
  fiber:Fiber,
  children:(PreactElement|PreactTextElement)[]
  ) => {
    let oldFiber = fiber.alternate && fiber.alternate.child
    let prevSibling:Fiber|null = null

    children.forEach((el,index)=>{
      let newFiber:Fiber|null = null
      if(oldFiber != null){
        const sameType = oldFiber && el  && el.type === oldFiber.type

        if(sameType){
           // in this condition element and oldFiber is exist and
           // both types are equal maybe props are changed
          newFiber = {
            type:oldFiber.type,
            props:el.props, // assign new props 
            dom:oldFiber.dom,
            parent:fiber,
            alternate:oldFiber,
            effectTag:"UPDATE",
            child:null,
            sibling:null
          }
        }

        if(el && !sameType ){
          newFiber = {
            type:el.type,
            props:el.props, 
            dom:null,
            parent:fiber,
            alternate:null,
            effectTag:"PLACEMENT",
            child:null,
            sibling:null
          }
        }

        if(oldFiber && !sameType){
          oldFiber.effectTag = "DELETION"
          deletion.push(oldFiber)
        }

        if(oldFiber){
          oldFiber = oldFiber.sibling
          newFiber = {
            type:el.type,
            props:el.props, 
            dom:null,
            parent:fiber,
            alternate:null,
            child:null,
            sibling:null
          }
        }


        if (index === 0){
          fiber.child = newFiber
        }else{
          if(prevSibling){
            prevSibling.sibling = newFiber
          }
        }
        prevSibling = newFiber
      }else{
        // create a first render dom
         
         newFiber = {
          type:el.type,
          props:el.props,
          parent:fiber,
          dom:null,
          child:null,
          sibling:null,
          alternate:null
        
        }
        newFiber.alternate = newFiber
        if (index === 0){
          fiber.child = newFiber
        }else{
          if(prevSibling){
            prevSibling.sibling = newFiber
          }
        }
        prevSibling = newFiber

        return
      }

  })


}

if i wrong please tell me :)

Updated child element gets appended to the end of the parent node.

If my updated element is not the last child, it is pushed to the last due to appendChild. Although we delete the updated element's dom from the parent dom, we are still appending the updated element's dom to the end.

Eg
<div id="parent"> <h2 title="child">Chapter 4 (Reconciliation)</h2> {update ? <span id="span1">span1</span> : <div id="div1">div1</div>} <div id="div2">div2</div> <div>
In the above case, the span gets appended as the last child of the parent div instead of being the 2nd child when the update becomes true. Should we be using "repalceChild" instead?

Possible Starvation Issues

I think i might have come across some starvation issues for both the linked React and Didact demos on my machine.

In one scenario i open page and the section(with text content) below the solar system never gets to render, in another scenario they do get to render but only on cycles where i either switch tabs(enough idle time?) or some other factor contributing to freeing up CPU cycles for it to render(initial) or update.

The synchronous version does not share the same issue.

It might make sense to open an issue in React as well if the issue(assuming i'm not mistake) is not related to the implementation details of the specific demo.

Hardware Overview:
Model Name:             MacBook Air
Model Identifier:       MacBookAir6,1
Processor Name:         Intel Core i5
Processor Speed:        1.3 GHz
Number of Processors:   1
Total Number of Cores:  2
L2 Cache (per Core):    256 KB
L3 Cache:               3 MB
Memory:                 4 GB
Boot ROM Version:       MBA61.0099.B33
SMC Version (system):   2.12f143
Serial Number (system): C02M32TSF5N8
Hardware UUID:          B47DCA38-89A5-5C73-9E7D-4E47AEE0320B

How to handle styling?

How do I handle inline styling?
currently something like

<div style{{background:"black"}}></div>

gets converted to

<div style></div>

updateDom in createDom function

I don't understand why we excute 'updateDom' in the function 'createDom'.It seems that we would change the dom before 'commit',and that should not happen in 'performUnitOfWork'
image

Minor issue in reconciler commitWork

Hi,

again, thanks for this very concise and understandable introduction.

One minor issue is this, it looks like

  } else if (fiber.effectTag == UPDATE) { 

should have been

  } else if (fiber.effectTag == UPDATE && fiber.tag == HOST_COMPONENT) { 

Code breaks

Copied the whole code for a test and seems to be broken at the point where we try to do the actual work.
return (
<h1 onClick={() => setState(c => c + 1)}>
Count: {state}

)

At this point my browser says Uncaught SyntaxError: Unexpected token '<'at the point we want to render the html as JSX.

commit deletion

Hello, I saw this repo for reverse-engineering or creating your own React library. It was a great project, but I have a question.

In this specific line:
https://github.com/pomber/didact/blob/master/didact.js#L136

function commitDeletion(fiber, domParent) {
  if (fiber.dom) {
    domParent.removeChild(fiber.dom)
  } else {
    commitDeletion(fiber.child, domParent)
  }
}

How does commitDeletion perform on sibling fibers of the given child fiber?

Why does set state always start the work from root again

Awesome blog post! It has been the best guide that I've ever read and really helped me understand the internals of React Fiber architecture.

One thing that I notice is that inside the useState, the setState will always set nextUnitOfWork = wipRoot, which means Didact will reconcile from the root. And inside updateFunctionComponent, the function component will always call fiber.type(fiber.props) which will cause the component re-render. But I believe this is not the case in React?

For example, we have this structure: https://playcode.io/1603467

<Parent>
  <Children />
</Parent>

const Parent = ({ children }) => {
  console.log('parent re-render')

  return <div>{children}</div>
}

const Children = (props) => {
  const [state, setState] = useState(0);
  console.log('child re-render')

  return <button onClick={() => setState(state+1)}>Click</button>
}

In actual React, when the <Children> button is clicked and setState is invoked, the <Parent> component will not-rerender. It is reflected by the parent console.log, which doesn't run again.

So my question is, how does Didact differ from React in this case? Which React's feature is not implemented in Didact?
Thanks

Use state hook not working on functional component

Hi there, I was having problems implementing the Didactjs so at some point I decided to just copy the intire file and a got an error

Error: Uncaught TypeError: Cannot read properties of null (reading 'alternate')

Context:

function useState(initial) {
  const oldHook =
    wipFiber.alternate &&  // <- Error happened here
    wipFiber.alternate.hooks &&
    wipFiber.alternate.hooks[hookIndex]
  const hook = {
    state: oldHook ? oldHook.state : initial,
    queue: [],
  }
...
}

My main file:

import Didact from './lib.mjs'

function App(props = { title: 'title' }){
  const [ counter, setCounter ] = Didact.useState(0)
  return Didact.createElement(
    'div',
    null,
    Didact.createElement(
      'h1',
      null,
      `${props.title}: ${counter}`
    ),
    Didact.createElement(
      'div',
      null, 
      Didact.createElement(
        'button',
        { onClick: () => console.log('click') },
        '+'
      ),
      Didact.createElement(
        'button',
        null,
        '-'
      )
    )
  )
}

Didact.render(App({ title: 'some' }), document.getElementById('root'))

What I've tried:

I tried to make one more verification

From:

const oldHook = wipFiber.alternate && wipFiber.alternate.hooks ...

To:

const oldHook = wipFiber && wipFiber.alternate && wipFiber.alternate.hooks ...

But then i got another error:

Error: Uncaught TypeError: Cannot read properties of null (reading 'hooks')

Context:

function useState(initial) {
  ...
  wipFiber.hooks.push(hook) // <- Error happened here
  hookIndex++
  return [hook.state, setState]
}

Then I tried a bunch of another thing but got nowhere, so I hope find some answers here

Confusing re-assignment

Hi, thank you for your tutorial I am enjoying it. So far so good but I have confusion on this part.

    if (index === 0) {
      wipFiber.child = newFiber
    } else if (element) {
     // even we set this we are still going to overwrite it. so what's the point?
      prevSibling.sibling = newFiber
    }
   // in here we are overwriting the whole object
   // that means `prevSibling.sibling` will be gone
    prevSibling = newFiber

Cheers!

commitWork function should return after commitDeletion(anOldFiber, domParent)

function commitWork(fiber) {
  if (!fiber) {
    return
  }

  let domParentFiber = fiber.parent
  while (!domParentFiber.dom) {
    domParentFiber = domParentFiber.parent
  }
  const domParent = domParentFiber.dom

  if (
    fiber.effectTag === "PLACEMENT" &&
    fiber.dom != null
  ) {
    domParent.appendChild(fiber.dom)
  } else if (
    fiber.effectTag === "UPDATE" &&
    fiber.dom != null
  ) {
    updateDom(
      fiber.dom,
      fiber.alternate.props,
      fiber.props
    )
  } else if (fiber.effectTag === "DELETION") {
    commitDeletion(fiber, domParent)

    // function should return at this moment
    return
  }

  commitWork(fiber.child)
  commitWork(fiber.sibling)
}

let's call the fiber to be deleted oldFiber

if commitWork function didnt return after commitDeletion(oldFiber, domParent), it will commitWork(oldFiber.child) and commitWork(oldFiber.sibling).

This may cause a terrible bug, because u dont know what type is oldFiber.child.effectTag or oldFiber.sibiling.effectTag

and commitWork function dont know the two fibers are old fibers and will treat them as current fiber to process.

Why can not use '!==' here ?

function reconcileChildren(wipFiber, elements) {
  let index = 0;
  let oldFiber = wipFiber.alternate && wipFiber.alternate.child;
  let prevSibling = null;

  while (index < elements.length || oldFiber != null) {
    const element = elements[index];
    let newFiber = null;

    const sameType = oldFiber && element && element.type == oldFiber.type;

    if (sameType) {
      newFiber = {
        type: oldFiber.type,
        props: element.props,
        dom: oldFiber.dom,
        parent: wipFiber,
        alternate: oldFiber,
        effectTag: "UPDATE"
      };
    }
    if (element && !sameType) {
      newFiber = {
        type: element.type,
        props: element.props,
        dom: null,
        parent: wipFiber,
        alternate: null,
        effectTag: "PLACEMENT"
      };
    }
    if (oldFiber && !sameType) {
      oldFiber.effectTag = "DELETION";
      deletions.push(oldFiber);
    }

    if (oldFiber) {
      oldFiber = oldFiber.sibling;
    }

    if (index === 0) {
      wipFiber.child = newFiber;
    } else if (element) {
      prevSibling.sibling = newFiber;
    }

    prevSibling = newFiber;
    index++;
  }
}

When I use '!==' like

 while (index < elements.length || oldFiber !== null) {
...
}

and When I input and then I can't continue typing, the browser is also stuck. Why ?

Buttons not working as expected

Hi. I have come across an issue. The following code is the only component I render:

function Counter() {
  const [count, setCount] = Didact.useState(1);
  return (
    <div>
      <h1>Count</h1>
      <botton onClick={() => setCount((c) => c + 1)}>+</button>
      <p>{count}</p>
      <botton onClick={() => setCount((c) => c - 1)}>-</button>
    </div>
  );
}

This code gives me this error:

/src/index.js: Expected corresponding JSX closing tag for <botton> (278:54)
276 |       <p onClick={() => setCount((c) => c + 1)}>+</p>
277 |       <p>{count}</p>
278 |       <botton onClick={() => setCount((c) => c - 1)}>-</button>
       |                                                       ^
279 |     </div>
280 |   );
281 | }

But this is weird because if I use p tag for buttons, everything works as expected.

An awful question... IE11...

Hey Rodrigo, thanks so much for providing this + tutorial so useful! - I've been looking for a really stripped back state management solution like this I can sideload on to my little js apps (the fact that it supports jsx is a bonus).

I'm actually building a JS library which is going into some software out of my control - and some of those users are going to require IE11 support (it's is a front end app going on a variety of website types)...

My thinking was, for those cases, just to recommend a bunch of polyfills (not caring about performance so much etc) to tick that box... But I've come across an issue I've spent so long on and can't figure out.

After loading up the usual polyfills (+ requestIdleCallback), it seems that the demo supplied - <Counter /> doesn't work.

When you click on it, the value just stays the same.

If you wrap the { state } in a node like this: <span>{ state }</span> it seems to work without issue... but naturally that's not practical and an odd restriction.

What I've managed to figure out is (maybe I've got it all wrong though...), somewhere in the reconcileChildren function things are going wrong (for IE11), and what would be two sibling text nodes:
Count: and 10 are merged into 1 dom reference:
Count: 10

I would usually not bother even trying to get this working on IE11 and move on, but it seems its about 1 line of code away from being polyfill-able...! (and at only a few kb this fits my needs perfectly)

Any ideas would be much appreciated...

And if it wasn't clear, I'm not enjoying asking about IE11... :)

keys implementation?

Hi. I’m wondering if you considered implementing the react key prop? Wondering what that looks like under the hood and haven’t found an approachable resource for it yet.

Thanks for the blog posts/implementation!

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.