工程(Koa、koa-router、sequelizejs、sqlite3)里有这么一段函数作为路由的 handler。 向 ret 对象里插入新的属性,循环插入的过程可以看到正常执行,但循环之后返回的结果却是 {}。
"use strict"
var Host = require('../model/Host.js');
module.exports = {
getList: function* ({
platform = 'audit'
}) {
var hosts = yield Host.findAll();// 通过 sequelize 模块读取数据库
var ret = {};
hosts.forEach( host => { // ? 难道这里有异步?
host = host.dataValues;
let owner = host.owner;
if (!ret[owner]) {
ret[owner] = [];
}
ret[owner].push( host );
console.log( ret[owner] );// 此处可以正常打印出 push 进去的 对象
});
console.log('ret', ret )// {} 这里竟然为空(如果放到 setTimeout 里,输出才符合预期)
return ret;
}
}
forEach没有异步。。。。是自己数据问题吧
大神,这是ES6语法来的。箭头函数。
hosts可能不是个raw Array,可能是一个具有类似array接口的东西,forEach实际是异步执行的实现。上面都是我猜的。
@valaxy 我也觉得诡异,直觉是与 yield 有关,我对 generator 不太熟悉。
@anotherWill 在箭头函数内访问 ret 变量符合预期,在循环之后 ret 就是 {}。但是加了 setTimeout 又符合预期。
@g8up es6的作用域不同吧。es6有块级作用域。
are u sure?
去除 getList 的参数后,一切平静了。
@valaxy 这个靠谱…
yield Host.findAll();/ 这个方法里面你有封装成Promise吗
@c15881291595 sequelize的查询方法返回的都是Promise
foreach里面的回调不是立即执行,但下面的console.log是立即执行的,那么输出的结果就是尚未被处理的,如果你把foreach改成for循环就能得到你想要的结果
又发现,将 forEach 抽离成函数来调用,一切就能正常:
function groupByOwner(hosts) {
var result = {};
hosts.forEach(host => {
host = host.dataValues;
var owner = host.owner;
if (!result[owner]) {
result[owner] = [];
}
result[owner].push(host);
});
return result;
}
module.exports = {
get: function* ({
platform = 'audit'
}) {
var hosts = yield Host.findAll({
attributes: ['host', 'port', 'root', 'owner', 'platform']
});
return groupByOwner(hosts);
}
}
forEach(function(){}.bind(this));试试这样。
需要理解generator和promise。 genrator结合promise可以同步书写异步代码。
yield是generator的语法写法。 可以yield一个promise,也可以yield一个立即数。 如果要实现异步编程,是通过yield一个promise实现的 如果yield一个立即数,需要setTimeout(0) 要切断上下文
@g8up 名字很屌啊,之前遇到过类似,写了下心得,async await与yield的混合使用
我测试的是没有问题啊,测试代码如下
'use strict';
const co = require('co');
//虚假构造了一个findAll函数,反正只要返回的是promise就行了
function findAll() {
return new Promise(function (resolve, reject) {
let arr = [];
for (let i = 0; i < 2; i++) {
let tmp = {
dataValues: {
owner: i + ': hyj'
}
};
arr.push(tmp);
}
resolve(arr);
});
}
//此处基copy楼主的代码
const obj = {
getList: function * () {
var hosts = yield findAll();// 通过 sequelize 模块读取数据库
var ret = {};
hosts.forEach(host => { // ? 难道这里有异步?
host = host.dataValues;
let owner = host.owner;
if (!ret[owner]) {
ret[owner] = [];
}
ret[owner].push(host);
console.log(ret[owner]);// 此处可以正常打印出 push 进去的 对象
});
//此处输出正常,为:ret { '0: hyj': [ { owner: '0: hyj' } ], '1: hyj': [ { owner: '1: hyj' } ] }
console.log('ret', ret);
return ret;
}
};
//使用co执行,结果正常
co(obj.getList).catch(err=>console.error(err));
//把obj函数放到另一个js文件里module.exports出来,使用co执行,结果同样正常
//co(require('./tetsYiled.js').getList).catch(err=>console.error(err));