LazyMan问题与解法
http://mp.weixin.qq.com/s/drNGvLZddQztcUzSh8OsSw
给出了一道题目,并给出了解法:
题目:
实现一个LazyMan,可以按照以下方式调用:
LazyMan(“Hank”)输出:
Hi! This is Hank!
LazyMan(“Hank”).sleep(10).eat(“dinner”)输出
Hi! This is Hank!
//等待10秒..
Wake up after 10
Eat dinner~
LazyMan(“Hank”).eat(“dinner”).eat(“supper”)输出
Hi This is Hank!
Eat dinner~
Eat supper~
LazyMan(“Hank”).sleepFirst(5).eat(“supper”)输出
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper
以此类推。
这是典型的JavaScript流程控制,问题的关键是如何实现任务的顺序执行。在Express有一个类似的东西叫中间件,这个中间件和我们这里的吃饭、睡觉等任务很类似,每一个中间件执行完成后会调用next()函数,这个函数用来调用下一个中间件。
对于这个问题,我们也可以利用相似的思路来解决,首先创建一个任务队列,然后利用next()函数来控制任务的顺序执行:
function _LazyMan(name) { this.tasks = []; var self = this; var fn =(function(n){ var name = n; return function(){ console.log("Hi! This is " + name + "!"); self.next(); } })(name); this.tasks.push(fn); setTimeout(function(){ self.next(); }, 0); // 在下一个事件循环启动任务 } /* 事件调度函数 */ _LazyMan.prototype.next = function() { var fn = this.tasks.shift(); fn && fn(); } _LazyMan.prototype.eat = function(name) { var self = this; var fn =(function(name){ return function(){ console.log("Eat " + name + "~"); self.next() } })(name); this.tasks.push(fn); return this; // 实现链式调用 } _LazyMan.prototype.sleep = function(time) { var self = this; var fn = (function(time){ return function() { setTimeout(function(){ console.log("Wake up after " + time + "s!"); self.next(); }, time * 1000); } })(time); this.tasks.push(fn); return this; } _LazyMan.prototype.sleepFirst = function(time) { var self = this; var fn = (function(time) { return function() { setTimeout(function() { console.log("Wake up after " + time + "s!"); self.next(); }, time * 1000); } })(time); this.tasks.unshift(fn); return this; } /* 封装 */ function LazyMan(name){ return new _LazyMan(name); }
Express中间件
http://www.expressjs.com.cn/guide/using-middleware.html
Express 是一个自身功能极简,完全是由路由和中间件构成一个的 web 开发框架:从本质上来说,一个 Express 应用就是在调用各种中间件。
中间件(Middleware) 是一个函数,它可以访问请求对象(request object (
req
)), 响应对象(response object (res
)), 和 web 应用中处于请求-响应循环流程中的中间件,一般被命名为next
的变量。中间件的功能包括:
- 执行任何代码。
- 修改请求和响应对象。
- 终结请求-响应循环。
- 调用堆栈中的下一个中间件。
如果当前中间件没有终结请求-响应循环,则必须调用
next()
方法将控制权交给下一个中间件,否则请求就会挂起。
Express 应用可使用如下几种中间件:
使用可选则挂载路径,可在应用级别或路由级别装载中间件。另外,你还可以同时装在一系列中间件函数,从而在一个挂载点上创建一个子中间件栈。
应用级中间件
应用级中间件绑定到 app 对象 使用 app.use()
和 app.METHOD()
, 其中, METHOD
是需要处理的 HTTP 请求的方法,例如 GET, PUT, POST 等等,全部小写。例如:
var app = express(); // 没有挂载路径的中间件,应用的每个请求都会执行该中间件 app.use(function (req, res, next) { console.log('Time:', Date.now()); next(); }); // 挂载至 /user/:id 的中间件,任何指向 /user/:id 的请求都会执行它 app.use('/user/:id', function (req, res, next) { console.log('Request Type:', req.method); next(); }); // 路由和句柄函数(中间件系统),处理指向 /user/:id 的 GET 请求 app.get('/user/:id', function (req, res, next) { res.send('USER'); }); 下面这个例子展示了在一个挂载点装载一组中间件。 // 一个中间件栈,对任何指向 /user/:id 的 HTTP 请求打印出相关信息 app.use('/user/:id', function(req, res, next) { console.log('Request URL:', req.originalUrl); next(); }, function (req, res, next) { console.log('Request Type:', req.method); next(); });
lua APITools middleware
https://docs.apitools.com/docs/middleware/index.html#lua-api-docs
We've seen how to proxy HTTP(s) requests through APItools and now we're going to add a whole new layer: applying transformations both to the HTTP(s) requests and responses. You can do that with middleware, small snippets of lua code that will control the transactions in different points of the process.
Middleware can be helpful for many different things, as for example:
- Creating alerts and other types of notifications - Fixtures - Transforming data formats on the fly - Avoiding rate limits - Authenticating apps with any API - ... you name it!
They also come in handy, for example, when getting started with a new API because you can quickly see what others are using a given API for and get your hands on it their middleware.
https://github.com/APItools/middleware/tree/master/middleware
例如 404 alert 中间件
return function (request, next_middleware) local five_mins = 60 * 5 local res = next_middleware() local last_mail = bucket.middleware.get('last_mail') if res.status == 404 and (not last_mail or last_mail < time.now() - five_mins) then send.mail('[email protected]', "A 404 has ocurred", "a 404 error happened in " .. request.uri_full .. ' see full trace: ' .. trace.link) bucket.middleware.set('last_mail', time.now()) end return res end
CORS中间件
return function (request, next_middleware) local res = next_middleware() -- Allow origin from certain domains (change as required) res.headers['Access-Control-Allow-Origin'] = "http://domain1.com http://domain2.com" -- Anable all domains (uncomment and comment the previous one if required) -- res.headers['Access-Control-Allow-Origin'] = "*" return res end
图片Lazy加载技术:
http://code.ciaoca.com/jquery/lazyload/
基于 jQuery 的图片延迟加载插件,在用户滚动页面到图片之后才进行加载。
对于有较多的图片的网页,使用图片延迟加载,能有效的提高页面加载速度。
载入 JavaScript 文件 <script src="jquery.js"></script> <script src="jquery.lazyload.js"></script> 修改 HTML 代码中需要延迟加载的 IMG 标签 <!-- 将真实图片地址写在 data-original 属性中,而 src 属性中的图片换成占位符的图片(例如 1x1 像素的灰色图片或者 loading 的 gif 图片) 添加 class="lazy" 用于区别哪些图片需要延时加载,当然你也可以换成别的关键词,修改的同时记得修改调用时的 jQuery 选择器 添加 width 和 height 属性有助于在图片未加载时占满所需要的空间 --> <img class="lazy" src="grey.gif" data-original="example.jpg" width="640" heigh="480"> 调用 Lazy Load $('img.lazy').lazyload();
Lazy evaluation技术
http://www.cnblogs.com/Wayou/p/lazy-evaluation.html
延迟求值带来的另一个好处是延迟执行。无论何时你写了段链式代码,只有在显式地调用了
.value()
后才会真正执行。这样一来,在数据源需要异步去拉取的情况下,可以保证我们处理的是最新的数据。
var wallet = _(assets).filter(ownedBy('me')) .pluck('value') .reduce(sum); $json.get("/new/assets").success(function(data) { assets.push.apply(assets, data); // 更新数据源 wallet.value(); // 返回的结果是最新的 });
而且这种机制在某些情况下也会提高执行效果。我们可以老早发送一个请求获取数据,然后指定一个精确的时间来执行。
http://danieltao.com/lazy.js/
Asynchronous iteration
You've probably seen code snippets before that show how to iterate over an array asynchronously in JavaScript. But have you seen an example packed full of map-y, filter-y goodness like this?
var asyncSequence = Lazy(array)
.async(100) // specifies a 100-millisecond interval between each element
.map(inc)
.filter(isEven)
.take(20);
// This function returns immediately and begins iterating over the sequence asynchronously.
asyncSequence.each(function(e) {
console.log(new Date().getMilliseconds() + ": " + e);
});
function inc(x) { return x + 1; }
function isEven(x) { return x % 2 === 0; }
Python Lazy Evaluation
https://en.wikipedia.org/wiki/Lazy_evaluation
The benefits of lazy evaluation include:
- The ability to define control flow (structures) as abstractions instead of primitives.
- The ability to define potentially infinite data structures. This allows for more straightforward implementation of some algorithms.
- Performance increases by avoiding needless calculations, and error conditions in evaluating compound expressions.
In Python 3.x the
range()
function[18] returns a special range object which computes elements of the list on demand. Elements of the range object are only generated when they are needed (e.g., whenprint(r[3])
is evaluated in the following example), so this is an example of lazy or deferred evaluation:>>> r = range(10) >>> print(r) range(0, 10) >>> print(r[3]) 3
- This change to lazy evaluation saves execution time for large ranges which may never be fully referenced and memory usage for large ranges where only one or a few elements are needed at any time.
其它实现Lazy问题的思路
本题中, Lazy问题是借助 原生js语法实现, 可在浏览器端执行。
如果不考虑兼容性, 还可以考虑一下实现方法:
1、 使用reactJS实现, 控制流。
2、 Promise
3、 async 和 await