ES6 的“奇葩”执行,yield 相关
发布于 9 年前 作者 g8up 7824 次预览 最后一次回复是 9 年前 来自 问答
工程(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;
}
}
18 回复
forEach没有异步。。。。是自己数据问题吧
大神,这是ES6语法来的。箭头函数。
hosts可能不是个raw Array,可能是一个具有类似array接口的东西,forEach实际是异步执行的实现。上面都是我猜的。
@valaxy 我也觉得诡异,直觉是与 yield 有关,我对 generator 不太熟悉。
@anotherWill 在箭头函数内访问 ret 变量符合预期,在循环之后 ret 就是 {}。但是加了 setTimeout 又符合预期。
@g8up es6的作用域不同吧。es6有块级作用域。
are u sure?
去除 getList 的参数后,一切平静了。
@valaxy 这个靠谱…
那他们的打印顺序呢?
如果 console.log(ret) 在后面的话,没理由里面没东西啊。
sequelize 不可能去替代 foreach 函数的我觉得。 @magicdawn @valaxy
yield Host.findAll();/ 这个方法里面你有封装成Promise吗
@c15881291595 sequelize的查询方法返回的都是Promise
foreach里面的回调不是立即执行,但下面的console.log是立即执行的,那么输出的结果就是尚未被处理的,如果你把foreach改成for循环就能得到你想要的结果
又发现,将 forEach 抽离成函数来调用,一切就能正常:
forEach(function(){}.bind(this));试试这样。
需要理解generator和promise。 genrator结合promise可以同步书写异步代码。
yield是generator的语法写法。 可以yield一个promise,也可以yield一个立即数。 如果要实现异步编程,是通过yield一个promise实现的 如果yield一个立即数,需要setTimeout(0) 要切断上下文
@g8up 名字很屌啊,之前遇到过类似,写了下心得,async await与yield的混合使用
我测试的是没有问题啊,测试代码如下