零、关于异步
如图,是一个传统nodejs项目中比较容易看到的一种编程风格,其原因是因为nodejs底层的很多异步方法都是通过配合回调方法来实现的。理解异步我们必须掌握以下几个知识点:
1、单线程
JavaScript的引擎是单线程的,即无论是在浏览器环境还是基于JavaScript引擎的nodejs服务器环境有且仅有一段代码正被执行,JavaScript引擎不会同时执行a函数的代码和b函数的代码。
2、JavaScript轮询机制(主线程 VS Event Loop线程)
轮询(event loop)简单说,就是在程序中设置两个线程:一个负责程序本身的运行,称为"主线程";另一个负责主线程与其他进程(主要是各种I/O操作)的通信,被称为"Event Loop线程"(可以译为"消息线程")。
就是说执行我们程序员写的代码的是主线程,当主线程遇到io操作的时候,主线程就通知Event Loop线程去执行相应的I/O程序,自己则继续执行其他代码,当Event Loop线程把io任务完成后会主动告诉主线程我已经执行完了,主线程收到通知后会调用事先准备好的回调函数,完成整个任务。
基于以上原因早期的nodejs 代码会存在大量的callback函数嵌套,这些callback正是为主线程在收到Event Loop线程完成io操作后准备的回调函数。
3、如何与Event Loop线程打交道?
作为一个习惯了java多线程的程序员,这个问题其实困扰了我很久,淡实际上我们其实并不需要直接与Event Loop线程打交道,最起码短时间内你不必自己封装跟Event Loop线程打交道的异步方法。
大部分异步方法其实都已经封装好了,比如JavaScript ajax请求,或者http请求的http框架,或者数据库操作的orm框架等
4、callback引发的问题
由上图展开联想,当存在多层调用的时候,callback将会深层嵌套,给代码可读性和维护性造成困扰。
一、promise简介
promise是一种规范,一种解决callcack深层嵌套的方案,一种带有then方法支持链式操作的框架.
二、promise 用法
//返回json格式字符串
exports.get = function (url, data) {
var deferred = Q.defer();
data = data || {};
http.get('http://' + url.host + ':' + url.port + url.path + '?' + querystring.stringify(data), function (res) {
var result = '';
res.setEncoding('utf8');
res.on('data', function (chunk) {
result += chunk;
});
res.on('end', function () {
var statusCode = res.statusCode;
if (statusCode === 200) {
result = result ? JSON.parse(result) : false;
deferred.resolve(result);
} else {
deferred.reject("get error statusCode: " + statusCode);
}
});
}).on('error', function (e) {
console.log("调用api 失败:" + e);
deferred.reject('get Error:' + e.message);
});
return deferred.promise;
};
三、promise链式写法
通过链式写法调用上面的get方法
/**
* 进入商品详情页面
*/
exports.detail = function (req, res) {
console.log("enter method product.detail");
var query = req.query;
var promise = productService.getProductById(query.id);
var product = {};
promise.then(function (result) {
product = result;
var query = {
"productListType": "BOSS_BRAND_PRODUCT_LIST",
"sort": "realSupportNum-desc"
};
return productService.getProductListById(result.brandId + "-" + result.id, query);
}).then(function (result) {
console.log(result);
console.log(product);
res.render("product/product", {
product: product,
brandProducts: result.datas
});
}).catch(function (e) {
product.status = 0;
console.log("获取商品详情失败" + e);
res.json("出错了");
});
};
来源:oschina
链接:https://my.oschina.net/u/1265394/blog/605957