博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ROCORE, 生成器,惰性求值,科技进步改变异步编程难题
阅读量:7015 次
发布时间:2019-06-28

本文共 8664 字,大约阅读时间需要 28 分钟。

hot3.png

github: oscgit: oscpage:

福利: 目前想要运行ES6代码的话,可以用google/traceur-compiler将代码转译. 然后静待nodejs0.12. (这个代码是运行前完全编译的,所以不用担心解析性能问题)

单队列多任务自由切换?

如果你喜欢nodejs的干脆直接,又深陷异步回调的泥潭,不如试试ROCORE,一个采用生成器和惰性求值的轻量框架。

ROCORE更像是nodejs里的一个干净独立的模块,提供一组轻便好用性能不错的工具, 不会污染nodejs内核,也不进行任何封装。

任务和队列将是nodejs异步编程的主题,ROCORE提供了3个工具,使代码可以自由的在单队列多任务切换:

  • yield停止当前任务
  • next跳到下一个任务(如果有, 否则跳到最外部)
  • ynext返回到当前任务

下面是一组我最近完成的邮箱找回密码代码,当请求时会检测用户email是否已经注册,然后往用户邮箱发送一个临时会话id。 你会看到,整套代码只有if,没有else,代码完全是扁平的,只有一层。

  • 使用redis作为会话缓存服务器
  • 使用mongodb作为数据服务器

路由文件:

// route.jslet R = require('rocore');let userdb = require('../database/user');let session = require('../session');let validate = require('./validate');let cparser = require('../cookie-parser');let nodemailer = require('nodemailer');const FIND_MAIL_HOST = 'smtp.163.com';const FIND_MAIL_PORT = 465;const FIND_MAIL_USER = 'wtaaa@163.com';const FIND_MAIL_PWD  = 'abc123';const FIND_MAIL_FROM = 'wtaaa@163.com';const FIND_MAIL_SUBJECT = 'Hello ✔';const FIND_MAIL_BODY = '

Hello world ✔

get back password

';exports.send_mail = function* (ynext, next, req, res, mdb, rlci) { let email = req.body.email; let vd_email = validate.vemail(email); // invalid email if (!vd_email) { res.writeHead(200, 'OK', { 'content-type':'text/plain' }); res.end('invalid email'); yield next(); } // let yctx_ue = yield userdb.exists_bye(mdb, email, ynext); let yctx_ue = yield mdb.collection('users').findOne({ email:email }, { fields:{_id:1} }, ynext); let err_ue = yctx_ue[0]; let doc_ue = yctx_ue[1]; // mongo-server error if (err_ue) { res.writeHead(500); res.end('server error'); yield next(); } // email not exists if (!doc_ue) { res.writeHead(200, 'OK', { 'content-type':'text/plain' }); res.end('email not exists'); yield next(); } let transporter = nodemailer.createTransport({ host: FIND_MAIL_HOST, secure: true, // 使用 SSL port: FIND_MAIL_PORT, // SMTP 端口 auth: { user: FIND_MAIL_USER, pass: FIND_MAIL_PWD } }); let yctx_sm = yield transporter.sendMail({ from : FIND_MAIL_FROM, to : email, subject : FIND_MAIL_SUBJECT, html : FIND_MAIL_BODY.replace('{sid}', 'SID123456789ABCDEFGHIJKLMN') }, ynext); let err_sm = yctx_sm[0]; let info_sm = yctx_sm[1]; // send error if (err_sm) { res.writeHead(500); res.end('error'); yield next(); } // successful res.writeHead(200, 'OK'); res.end('OK'); //console.log('Message sent: ' + info_sm.response); yield next();};

单元测试:

let assert      = require('assert');let R           = require('rocore');let http        = require('http');let url         = require('url');let qs          = require('querystring');let uroute      = require('../../lib/route/user');let cparser     = require('../../lib/cookie-parser');let rcli        = require('redis').createClient();let MongoClient = require('mongodb').MongoClient;let server      = http.createServer();let app         = R.Application();let mdb         = null;server    .on('request', function (req, res) {        app.match(req, res);    })    ;app    .on('found', function (route, req, res) {        req.cookie = cparser.parse(req.headers.cookie);        var data = '';        req.setEncoding('utf8');        req.on('data', function (d) {             data += d;        });        req.on('end', function () {             req.body = qs.parse(data, '&', '=');             app.exec(route, req, res, mdb, rcli);        });    })    .post('/join', uroute.join)    .post('/userback', uroute.send_mail)    ;R.scc(function* (ynext) {    let yctx_mc = yield MongoClient.connect('mongodb://127.0.0.1:31000/test', { "poolSize":10 }, ynext);    let err_mc = yctx_mc[0];        if (err_mc) { throw err_mc; }    mdb = yctx_mc[1];    server.listen(8000);    // join user with full info     let res_jf = (yield R.request({        hostname: '127.0.0.1',        port: 8000,        path: '/join',        headers: {            'Content-Type': 'application/application/x-www-form-urlencoded'        },        method: 'post',        body: {            username: 'wt',            password: '123456',            password2: '123456',            email: 'wtaaa@163.com',            sex: 'male',            language: 'en'        }    }, ynext))[0];     let res_ue = (yield R.request({        hostname: '127.0.0.1',        port: 8000,        path: '/userback',        headers: {            'Content-Type': 'application/application/x-www-form-urlencoded'        },        method: 'post',        body: {            email: 'wtaaa@163.com'        }    }, ynext))[0];     assert.strictEqual(res_ue.body, 'OK');        process.exit(0);});

服务器如何配置呢?

遵循nodejs设计思想,rocore.Application提供事件注册的机制,服务器配置将会如下:

let R           = require('rocore');let http        = require('http');let url         = require('url');let qs          = require('querystring');let uroute      = require('../../lib/route/user');let cparser     = require('../../lib/cookie-parser');let rcli        = require('redis').createClient();let MongoClient = require('mongodb').MongoClient;let server      = http.createServer();let app         = R.Application();let mdb         = null;server    .on('request', function (req, res) {        app.match(req, res);    })    ;app    .on('found', function (route, req, res) {        req.cookie = cparser.parse(req.headers.cookie);        var data = '';        req.setEncoding('utf8');        req.on('data', function (d) {             data += d;        });        req.on('end', function () {             req.body = qs.parse(data, '&', '=');             app.exec(route, req, res, mdb, rcli);        });    })    .on('notfound', function (req, res) {        res.writeHead(404);        res.end('Could not found ' + url.parse(req.url).pathname);    })    .get('/', function* (ynext, next, req, res) {        res.writeHead(200, 'OK', { 'Content-Type':'text/html' });        res.end('/');    })    .post('/join', uroute.join)    .post('/login', uroute.login)    .post('/logout', uroute.is_login, uroute.logout)    ;R.scc(function* (ynext) {    let yctx_mc = yield MongoClient.connect('mongodb://127.0.0.1:31000/test', { "poolSize":10 }, ynext);    let err_mc = yctx_mc[0];    if (err_mc) { throw err_mc; }    mdb = yctx_mc[1];    server.listen(8000);});

更有趣的队列实验?

想要在队列的多任务中来去自如,那么下面的代码很有代表性:

let app    = require('../lib/rocore').Application();let assert = require('assert');let stack  = [];function test(x, callback) {    process.nextTick(function () {        callback(x);    });}app    .on('found', function (route, req, res) {        app.exec(route, req, res);    })    .on('finish', function (ynext, req, res) {        if (typeof ynext === 'function') {            ynext({ '0': 0 });        }    })    .post(        '/:user/ttt',         function* (ynext, next, req, res) {            let a = yield test(1, ynext); stack.push(a[0]);             let b = yield next(ynext);    stack.push(b[0][0]);             let c = yield test(2, ynext); stack.push(c[0]);             assert.deepEqual(stack, [ 1, 3, 5, 0, 6, 6, 4, 4, 2 ]);            process.exit(0);        },         function* (ynext, next, req, res) {            let a = yield test(3, ynext); stack.push(a[0]);             let b = yield next(ynext);    stack.push(b[0][0]);             let c = yield test(4, ynext); stack.push(c[0]);         },          function* (ynext, next, req, res) {            let a = yield test(5, ynext); stack.push(a[0]);             let b = yield next(ynext);    stack.push(b[0][0]);             let c = yield test(6, ynext); stack.push(c[0]);         }    )    ;// 1, 3, 5, 0, 6, 6, 4, 4, 2

更有利的异步任务控制工具?

  • rocore.scc(generator, [callback])
  • rocore.mcc(generator, [callback])

使用这两个工具可以帮助你随时完成任意的异步代码:

let assert = require('assert');let R      = require('../lib/rocore');function fA(a, callback) {    setTimeout(function () {        callback(a, 'aaa');    }, 1000);}function fB(b, callback) {    setTimeout(function () {        callback(b, 'bbb');    }, 1000);}R.scc(function* (ynext) {    let A = yield fA('a1', ynext);    assert.strictEqual(A[0], 'a1');      assert.strictEqual(A[1], 'aaa');      let B = yield fB('b1', ynext);    assert.strictEqual(B[0], 'b1');      assert.strictEqual(B[1], 'bbb');    let C = yield R.mcc(function* (ynext) {        yield fA('a2', ynext('a'));        yield fB('b2', ynext('b'));    }, ynext);    assert.strictEqual(C[0]['a'][0], 'a2');      assert.strictEqual(C[0]['a'][1], 'aaa');      assert.strictEqual(C[0]['b'][0], 'b2');    assert.strictEqual(C[0]['b'][1], 'bbb');          process.exit(0);});

转载于:https://my.oschina.net/tulayang/blog/362507

你可能感兴趣的文章
Codeforces Round #343 (Div. 2) D. Babaei and Birthday Cake 线段树维护dp
查看>>
ubuntu14安装redis
查看>>
DICOM:C-GET与C-MOVE对照剖析
查看>>
什么是跨域请求
查看>>
利用__index和__newindex实现默认值表、监控表、只读表(转)
查看>>
HDU 1247 Hat’s Words (字典树 && map)
查看>>
spring boot启动原理步骤分析
查看>>
用swift开发仪表盘控件(二)
查看>>
hadoop2.7.3+spark2.1.0+scala2.12.1环境搭建(3)http://www.cnblogs.com/liugh/p/6624491.html
查看>>
HTML学习笔记(五)
查看>>
把任意exe程序注册成windows系统服务
查看>>
第8章:归档与压缩
查看>>
jquery07
查看>>
Linux平台下RMAN异机恢复总结
查看>>
怎样给UINavigationBar加入button?
查看>>
mongodb 初学 索引
查看>>
每日一小练——二项式系数加法解
查看>>
django中的setting全局变量的导入
查看>>
常见的几种Flume日志收集场景实战
查看>>
Java深入 - Filter过滤器
查看>>