• 如何在GitHub”寻找灵感(fork)”
    • Lettuce构建过程
      • 需求
      • 计划
      • 实现第一个需求
        • 生成框架
        • 寻找
      • 实现第二个需求

    如何在GitHub”寻找灵感(fork)”

    重造轮子是重新创造一个已有的或是已被其他人优化的基本方法。

    最近萌发了一个想法写游戏引擎,之前想着做一个JavaScript前端框架。看看,这个思路是怎么来的。

    Lettuce构建过程

    Lettuce是一个简约的移动开发框架。

    故事的出发点是这样的:写了很多代码,用的都是框架,最后不知道收获什么了?事实也是如此,当自己做了一些项目之后,发现最后什么也没有收获到。于是,就想着做一个框架。

    需求

    有这样的几个前提

    • 为什么我只需要jQuery里的选择器、Ajax要引入那么重的库呢?
    • 为什么我只需要一个Template,却想着用Mustache
    • 为什么我需要一个Router,却要用Backbone呢?
    • 为什么我需要的是一个isObject函数,却要用到整个Underscore?

    我想要的只是一个简单的功能,而我不想引入一个庞大的库。换句话说,我只需要不同库里面的一小部分功能,而不是一个库。

    实际上想要的是:

    构建一个库,里面从不同的库里面抽取出不同的函数。

    计划

    这时候我参考了一本电子书《Build JavaScript FrameWork》,加上一些平时的需求,于是很快的就知道自己需要什么样的功能:

    • Promise 支持
    • Class类(ps:没有一个好的类使用的方式)
    • Template 一个简单的模板引擎
    • Router 用来控制页面的路由
    • Ajax 基本的Ajax Get/Post请求

    在做一些实际的项目中,还遇到了这样的一些功能支持:

    • Effect 简单的一些页面效果
    • AMD支持

    而我们有一个前提是要保持这个库尽可能的小、同时我们还需要有测试。

    实现第一个需求

    简单说说是如何实现一个简单的需求。

    生成框架

    因为Yeoman可以生成一个简单的轮廓,所以我们可以用它来生成这个项目的骨架。

    • Gulp
    • Jasmine

    寻找

    在GitHub上搜索了一个看到了下面的几个结果:

    • https://github.com/then/promise
    • https://github.com/reactphp/promise
    • https://github.com/kriskowal/q
    • https://github.com/petkaantonov/bluebird
    • https://github.com/cujojs/when

    但是显然,他们都太重了。事实上,对于一个库来说,80%的人只需要其中20%的代码。于是,找到了https://github.com/stackp/promisejs,看了看用法,这就是我们需要的功能:

    1. function late(n) {
    2. var p = new promise.Promise();
    3. setTimeout(function() {
    4. p.done(null, n);
    5. }, n);
    6. return p;
    7. }
    8. late(100).then(
    9. function(err, n) {
    10. return late(n + 200);
    11. }
    12. ).then(
    13. function(err, n) {
    14. return late(n + 300);
    15. }
    16. ).then(
    17. function(err, n) {
    18. return late(n + 400);
    19. }
    20. ).then(
    21. function(err, n) {
    22. alert(n);
    23. }
    24. );

    接着打开看看Promise对象,有我们需要的功能,但是又有一些功能超出我的需求。接着把自己不需要的需求去掉,这里函数最后就变成了

    1. function Promise() {
    2. this._callbacks = [];
    3. }
    4. Promise.prototype.then = function(func, context) {
    5. var p;
    6. if (this._isdone) {
    7. p = func.apply(context, this.result);
    8. } else {
    9. p = new Promise();
    10. this._callbacks.push(function () {
    11. var res = func.apply(context, arguments);
    12. if (res && typeof res.then === 'function') {
    13. res.then(p.done, p);
    14. }
    15. });
    16. }
    17. return p;
    18. };
    19. Promise.prototype.done = function() {
    20. this.result = arguments;
    21. this._isdone = true;
    22. for (var i = 0; i < this._callbacks.length; i++) {
    23. this._callbacks[i].apply(null, arguments);
    24. }
    25. this._callbacks = [];
    26. };
    27. var promise = {
    28. Promise: Promise
    29. };

    需要注意的是: License,不同的软件有不同的License,如MIT、GPL等等。最好能在遵循协议的情况下,使用别人的代码。

    实现第二个需求

    由于已经有了现有的很多库,所以就可以直接参照(抄)别人写的代码。

    1. Lettuce.get = function (url, callback) {
    2. Lettuce.send(url, 'GET', callback);
    3. };
    4. Lettuce.load = function (url, callback) {
    5. Lettuce.send(url, 'GET', callback);
    6. };
    7. Lettuce.post = function (url, data, callback) {
    8. Lettuce.send(url, 'POST', callback, data);
    9. };
    10. Lettuce.send = function (url, method, callback, data) {
    11. data = data || null;
    12. var request = new XMLHttpRequest();
    13. if (callback instanceof Function) {
    14. request.onreadystatechange = function () {
    15. if (request.readyState === 4 && (request.status === 200 || request.status === 0)) {
    16. callback(request.responseText);
    17. }
    18. };
    19. }
    20. request.open(method, url, true);
    21. if (data instanceof Object) {
    22. data = JSON.stringify(data);
    23. request.setRequestHeader('Content-Type', 'application/json');
    24. }
    25. request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    26. request.send(data);
    27. };