异步方法中map、forEach和for循环中带来的异步执行问题
2016-08-26 17:32
399 查看
关键词:map() forEach() for() 异步执行 res.jsonp()
CSDN个人博客:http://blog.csdn.net/sam976
代码如下:
页面发送请求http://127.0.0.1:3000/getdata时,jsonp返回的数据是空,也就
4000
是result为空。
结果如图所示:
首先可以肯定,查询结果不为空,因为查询条件是专门设定的。
我们知道Array.forEach .map是同步(阻塞)的,也就是在循环结束后,后面的语句才会被执行,如果按照这个逻辑,jsonp返回的result不会为空,那问题出在哪里?
这时候,会发现result打印的位置(红框部分)居然在array_test[i]结果之前,这和代码的顺序不符合呀!它变成了异步执行。
通过查询mongoose文档可以发现,Model.findOne([conditions], [projection], [options], [callback])是一个异步执行的函数,有结果就会调用callback。而node中的map()、forEach()、for()循环有一个特性:当其函数里面里面有回调它就变成异步。map就变成了这样,第一次循环开始,findOne查询数据库,不等有结果就开始第二次查询开始,…第三次查询开始,循环结束,不等有结果它就开始执行console.log(result),所以result为空,而且打印结果在array_test[i]之前。
为了证明分析对不对,我简单测了一下,既然findOne是异步函数,那么如果我在map中不用异步函数,是不是打印顺序和代码书写顺序就是一样的?
代码如下:
结果如下:
jsonp返回的result不为空
result的书序也和代码中书写顺序一样
到这里就可以看出,果然是异步的问题导致result为空。那怎么解决?
对集合中的每一个元素,执行异步操作,得到结果。所有的结果将汇总到最终的callback里。其实就是把异步都加到队列里, 等全都执行完了之后执行一个统一的回调,这样看起来就是同步的效果。
代码如下:
页面效果如下图,可以看到result有数据:
服务器控制台效果如下图,可以看到array_test打印在result前面,是同步的顺序:
更多关于async请查看官方文档或者github中文文档。
当然也有其他的方式解决这个问题,比如bluebird、asyncawait,这里不多加分析。
CSDN个人博客:http://blog.csdn.net/sam976
问题描述
在map循环中使用mongoose的Model.findOne查询mongodb数据库,查询到数据后使用res.jsonp响应。代码如下:
router.get('/getData', function(req, res) { var data=[1,2,3]; var result=data.map(function(v, i, a) { /*根据studentid到数据库中查询数据*/ Fee.findOne({ studentid: "57b525bc4e8d464803167da7" }, {}, function(err, fees) { if (err) return handleError(err); var array_test = []; array_test[i] = {}; array_test[i].number = v; array_test[i].fees = fees; /*打印查询结果*/ console.log('++++++array_test[i]++++++') console.log(array_test[i]) console.log('++++++array_test[i]++++++') return array_test[i]; }); }); /*result被赋予查询结果*/ console.log('-----result-----'); console.log(result); console.log('-----result-----'); res.jsonp({ one: 'aa', two: 'bb', three: result }); });
页面发送请求http://127.0.0.1:3000/getdata时,jsonp返回的数据是空,也就
4000
是result为空。
结果如图所示:
首先可以肯定,查询结果不为空,因为查询条件是专门设定的。
我们知道Array.forEach .map是同步(阻塞)的,也就是在循环结束后,后面的语句才会被执行,如果按照这个逻辑,jsonp返回的result不会为空,那问题出在哪里?
问题分析
经过分析,查询结果确实不为空,这个可以从服务器控制台打印结果看出。如图黄色部分即为被赋予查询结果的array_test[i]:这时候,会发现result打印的位置(红框部分)居然在array_test[i]结果之前,这和代码的顺序不符合呀!它变成了异步执行。
通过查询mongoose文档可以发现,Model.findOne([conditions], [projection], [options], [callback])是一个异步执行的函数,有结果就会调用callback。而node中的map()、forEach()、for()循环有一个特性:当其函数里面里面有回调它就变成异步。map就变成了这样,第一次循环开始,findOne查询数据库,不等有结果就开始第二次查询开始,…第三次查询开始,循环结束,不等有结果它就开始执行console.log(result),所以result为空,而且打印结果在array_test[i]之前。
为了证明分析对不对,我简单测了一下,既然findOne是异步函数,那么如果我在map中不用异步函数,是不是打印顺序和代码书写顺序就是一样的?
代码如下:
router.get('/getData', function(req, res) { var data = [1, 2, 3]; var result = data.map(function(v, i, a) { var array_test = []; array_test[i] = {}; array_test[i].number = v; array_test[i].fees = 'cc'; return array_test[i]; }); console.log('-----result-----'); console.log(result); console.log('-----result-----'); res.jsonp({ one: 'aa', two: 'bb', three: result }); });
结果如下:
jsonp返回的result不为空
result的书序也和代码中书写顺序一样
到这里就可以看出,果然是异步的问题导致result为空。那怎么解决?
解决方法
可以用async的map来处理这种情况,async是nodejs的一个组件,用来解决node的异步问题。而其中的map方法:对集合中的每一个元素,执行异步操作,得到结果。所有的结果将汇总到最终的callback里。其实就是把异步都加到队列里, 等全都执行完了之后执行一个统一的回调,这样看起来就是同步的效果。
代码如下:
/*这部分代码和前面代码不太一样,单纯只是为了演示async.map的效果如何。*/ router.get('/getData', function(req, res) { var data = [1, 2, 3]; var array_test = {}; async.map(data, function(v, callback) { /*根据studentid到数据库中查询数据*/ Fee.findOne({ studentid: "57b525bc4e8d464803167da7" }, {}, function(err, fees) { if (err) return handleError(err); array_test[v]=fees.studentid; console.log('++++++array_test++++++') console.log(array_test); console.log('++++++array_test++++++') callback(null, array_test); }); }, function(err, results) { console.log('-----result-----'); console.log(results); console.log('-----result-----'); res.jsonp({ one: 'aa', two: 'bb', three: results }); }); });
页面效果如下图,可以看到result有数据:
服务器控制台效果如下图,可以看到array_test打印在result前面,是同步的顺序:
更多关于async请查看官方文档或者github中文文档。
当然也有其他的方式解决这个问题,比如bluebird、asyncawait,这里不多加分析。
相关文章推荐
- js中的for循环与异步回调函数执行顺序问题
- AppLocale安装方法,及带来的中文软件执行问题解决办法
- 测试for和foreach的执行效率的问题
- 在foreach的判断条件里执行方法会有效率问题吗?
- 使用spring的@Async异步执行方法以及不执行问题
- 采用自执行的匿名函数解决for循环使用闭包的问题
- Java中for循环中执行顺序问题及break, continue用法
- 关于supermap api for Flex 中FeaturesLayer的clear方法连续执行167次后报空的问题
- 20130409学习_增强的for循环用法和map的常用方法
- 关于for循环的执行效率的问题
- JS之经典for循环闭包问题解决方法
- for和foreach的执行效率的问题之新发现
- “SET 命令设置的环境变量在 FOR 循环中始终为空”问题的原因与解决方法
- ajax回调函数执行顺序带来的同步异步问题
- 关于for 循环里 线程执行顺序问题
- phpcms2008 信息管理 Warning: Invalid argument supplied for foreach() in 问题的解决方法
- 在foreach的判断条件里执行方法会有效率问题吗?
- 解决VC6和VC2008的for循环变量作用域不同问题的一个方法
- ajax回调函数执行顺序带来的同步异步问题
- 采用自执行的匿名函数解决for循环使用闭包的问题