|
| 1 | +#如何在Github"寻找灵感(fork)" |
| 2 | + |
| 3 | +> 重造轮子是重新创造一个已有的或是已被其他人优化的基本方法。 |
| 4 | +
|
| 5 | +最近萌发了一个想法写游戏引擎,之前想着做一个JavaScript前端框架。看看,这个思路是怎么来的。 |
| 6 | + |
| 7 | +##一、[Lettuce](https://github.com/phodal/lettuce)构建过程 |
| 8 | + |
| 9 | +> Lettuce是一个简约的移动开发框架。 |
| 10 | +
|
| 11 | +故事的出发点是这样的:``写了很多代码,用的都是框架,最后不知道收获什么了``?事实也是如此,当自己做了一些项目之后,发现最后什么也没有收获到。于是,就想着做一个框架。 |
| 12 | + |
| 13 | +###需求 |
| 14 | + |
| 15 | +有这样的几个前提 |
| 16 | + |
| 17 | + - 为什么我只需要jQuery里的选择器、Ajax要引入那么重的库呢? |
| 18 | + - 为什么我只需要一个Template,却想着用Mustache |
| 19 | + - 为什么我需要一个Router,却要用Backbone呢? |
| 20 | + - 为什么我需要的是一个isObject函数,却要用到整个Underscore? |
| 21 | + |
| 22 | +我想要的只是一个简单的功能,而我不想引入一个庞大的库。换句话说,我只需要不同库里面的一小部分功能,而不是一个库。 |
| 23 | + |
| 24 | +实际上想要的是: |
| 25 | + |
| 26 | +> 构建一个库,里面从不同的库里面抽取出不同的函数。 |
| 27 | +
|
| 28 | +###计划 |
| 29 | + |
| 30 | +这时候我参考了一本电子书《Build JavaScript FrameWork》,加上一些平时的需求,于是很快的就知道自己需要什么样的功能: |
| 31 | + |
| 32 | + - Promise 支持 |
| 33 | + - Class类(ps:没有一个好的类使用的方式) |
| 34 | + - Template 一个简单的模板引擎 |
| 35 | + - Router 用来控制页面的路由 |
| 36 | + - Ajax 基本的Ajax Get/Post请求 |
| 37 | + |
| 38 | +在做一些实际的项目中,还遇到了这样的一些功能支持: |
| 39 | + |
| 40 | + - Effect 简单的一些页面效果 |
| 41 | + - AMD支持 |
| 42 | + |
| 43 | +而我们有一个前提是要保持这个库尽可能的小、同时我们还需要有测试。 |
| 44 | + |
| 45 | +###实现第一个需求 |
| 46 | + |
| 47 | +简单说说是如何实现一个简单的需求。 |
| 48 | + |
| 49 | +####生成框架 |
| 50 | + |
| 51 | +因为Yeoman可以生成一个简单的轮廓,所以我们可以用它来生成这个项目的骨架。 |
| 52 | + |
| 53 | + - Gulp |
| 54 | + - Jasmine |
| 55 | + |
| 56 | +####寻找 |
| 57 | + |
| 58 | +在Github上搜索了一个看到了下面的几个结果: |
| 59 | + |
| 60 | +- [https://github.com/then/promise](https://github.com/then/promise) |
| 61 | +- [https://github.com/reactphp/promise](https://github.com/reactphp/promise) |
| 62 | +- [https://github.com/kriskowal/q](https://github.com/kriskowal/q) |
| 63 | +- [https://github.com/petkaantonov/bluebird](https://github.com/petkaantonov/bluebird) |
| 64 | +- [https://github.com/cujojs/when](https://github.com/cujojs/when) |
| 65 | + |
| 66 | +但是显然,他们都太重了。事实上,对于一个库来说,80%的人只需要其中20%的代码。于是,找到了[https://github.com/stackp/promisejs](https://github.com/stackp/promisejs),看了看用法,这就是我们需要的功能: |
| 67 | + |
| 68 | + function late(n) { |
| 69 | + var p = new promise.Promise(); |
| 70 | + setTimeout(function() { |
| 71 | + p.done(null, n); |
| 72 | + }, n); |
| 73 | + return p; |
| 74 | + } |
| 75 | + |
| 76 | + late(100).then( |
| 77 | + function(err, n) { |
| 78 | + return late(n + 200); |
| 79 | + } |
| 80 | + ).then( |
| 81 | + function(err, n) { |
| 82 | + return late(n + 300); |
| 83 | + } |
| 84 | + ).then( |
| 85 | + function(err, n) { |
| 86 | + return late(n + 400); |
| 87 | + } |
| 88 | + ).then( |
| 89 | + function(err, n) { |
| 90 | + alert(n); |
| 91 | + } |
| 92 | + ); |
| 93 | + |
| 94 | +接着打开看看Promise对象,有我们需要的功能,但是又有一些功能超出我的需求。接着把自己不需要的需求去掉,这里函数最后就变成了 |
| 95 | + |
| 96 | + function Promise() { |
| 97 | + this._callbacks = []; |
| 98 | + } |
| 99 | + |
| 100 | + Promise.prototype.then = function(func, context) { |
| 101 | + var p; |
| 102 | + if (this._isdone) { |
| 103 | + p = func.apply(context, this.result); |
| 104 | + } else { |
| 105 | + p = new Promise(); |
| 106 | + this._callbacks.push(function () { |
| 107 | + var res = func.apply(context, arguments); |
| 108 | + if (res && typeof res.then === 'function') { |
| 109 | + res.then(p.done, p); |
| 110 | + } |
| 111 | + }); |
| 112 | + } |
| 113 | + return p; |
| 114 | + }; |
| 115 | + |
| 116 | + Promise.prototype.done = function() { |
| 117 | + this.result = arguments; |
| 118 | + this._isdone = true; |
| 119 | + for (var i = 0; i < this._callbacks.length; i++) { |
| 120 | + this._callbacks[i].apply(null, arguments); |
| 121 | + } |
| 122 | + this._callbacks = []; |
| 123 | + }; |
| 124 | + |
| 125 | + var promise = { |
| 126 | + Promise: Promise |
| 127 | + }; |
| 128 | + |
| 129 | +需要注意的是: ``License``,不同的软件有不同的License,如MIT、GPL等等。最好能在遵循协议的情况下,使用别人的代码。 |
| 130 | + |
| 131 | +###实现第二个需求 |
| 132 | + |
| 133 | +由于,现有的一些Ajax库都比较,最后只好参照着别人的代码自己实现。 |
| 134 | + |
| 135 | + Lettuce.get = function (url, callback) { |
| 136 | + Lettuce.send(url, 'GET', callback); |
| 137 | + }; |
| 138 | + |
| 139 | + Lettuce.load = function (url, callback) { |
| 140 | + Lettuce.send(url, 'GET', callback); |
| 141 | + }; |
| 142 | + |
| 143 | + Lettuce.post = function (url, data, callback) { |
| 144 | + Lettuce.send(url, 'POST', callback, data); |
| 145 | + }; |
| 146 | + |
| 147 | + Lettuce.send = function (url, method, callback, data) { |
| 148 | + data = data || null; |
| 149 | + var request = new XMLHttpRequest(); |
| 150 | + if (callback instanceof Function) { |
| 151 | + request.onreadystatechange = function () { |
| 152 | + if (request.readyState === 4 && (request.status === 200 || request.status === 0)) { |
| 153 | + callback(request.responseText); |
| 154 | + } |
| 155 | + }; |
| 156 | + } |
| 157 | + request.open(method, url, true); |
| 158 | + if (data instanceof Object) { |
| 159 | + data = JSON.stringify(data); |
| 160 | + request.setRequestHeader('Content-Type', 'application/json'); |
| 161 | + } |
| 162 | + request.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); |
| 163 | + request.send(data); |
| 164 | + }; |
| 165 | + |
0 commit comments