Javascript 带承诺的异步循环?
下面的代码注册了一系列socketio名称空间。部分逻辑依赖于通过sequelize进行的数据库调用,因此我需要使用Promissions。我希望当所有名为logic的构造函数都完成时,完整的承诺得到解决。但我的问题是,在emitInitialPackage函数解决之前,完整的承诺就解决了Javascript 带承诺的异步循环?,javascript,typescript,ecmascript-6,promise,es6-promise,Javascript,Typescript,Ecmascript 6,Promise,Es6 Promise,下面的代码注册了一系列socketio名称空间。部分逻辑依赖于通过sequelize进行的数据库调用,因此我需要使用Promissions。我希望当所有名为logic的构造函数都完成时,完整的承诺得到解决。但我的问题是,在emitInitialPackage函数解决之前,完整的承诺就解决了 export class demoClass { public complete: Promise<boolean>; server: any; constructor(
export class demoClass {
public complete: Promise<boolean>;
server: any;
constructor(io: any) {
this.server = io;
this.complete = Promise.resolve(db.Line.findAll()).then(lines => {
// do some mapping to generate routes and cells
this.registerEndPoints(routes, [], cells);
}).catch(err => console.log(err))
}
registerEndPoints(routes: Array<string>, nsps: Array<any>, cells: Array<string>) {
for (let i = 0; i < routes.length; i++) {
nsps.push(this.server.of('/api/testNamespace/' + routes[i]));
let that = this;
const nsp = nsps[i];
nsp.on('connection', function (socket) {
that.emitInitialPackage(nsps[i], routes[i], cells[i]);
});
}
}
emitInitialPackage(nsp: any, name: string, cell: any) {
return db.Line.find({/* Some sequelize params*/}).then(results => {
nsp.emit('value', results);
}).catch(err => console.log(err));
}
}
如何确保emitInitialPackage在完成解析之前已完成?若要等待registerEndPoints中所有操作的完成,此方法应返回可在db.Line.findAll操作后链接的承诺:
export class demoClass {
public complete: Promise<boolean>;
server: any;
constructor(io: any) {
this.server = io;
this.complete = Promise.resolve(db.Line.findAll()).then(lines => {
// return promise created by registerEndPoints method
return this.registerEndPoints(routes, [], cells);
}).catch(err => console.log(err))
}
registerEndPoints(routes: Array<string>, nsps: Array<any>, cells: Array<string>) {
const endPointPromises = routes.map((route, index) => {
// for each endpoint create Promise that gets resolved
// only when all work for endpoint is done
return new Promise((resolve) => {
nsps.push(this.server.of('/api/testNamespace/' + route));
const nsp = nsps[index];
nsp.on('connection', (socket) => {
// resolve promise when emitInitialPackage did its part of the work
this.emitInitialPackage(nsps[index], route, cells[index]).then(resolve);
});
});
});
return Promise.all(endPointPromises);
}
emitInitialPackage(nsp: any, name: string, cell: any) {
return db.Line.find({/* Some sequelize params*/}).then(results => {
nsp.emit('value', results);
}).catch(err => console.log(err));
}
}
有几个问题需要解决: 返回this.registerEndPoints返回的承诺,因此this.complete仅在该承诺解决时才会解决; 为nsps参数传递的[]参数没有作为参数的作用,因此您最好将该参数一起跳过; 关于“连接”的。。。函数应该被包装以返回一个承诺; for循环应该创建这些承诺,然后将它们传递给Promise.all以获得最终结果。地图可用于此; 如果有三个数组、路由、单元和NSP,它们在相同的索引处具有相关数据,那么这种结构就不好。更好的结构是有一个对象数组,每个对象有三个属性:路由、单元和nsp; bluebird是promises/A+兼容的,因此不需要将bluebird promise转换为原生JS promise。 以下是一些未经测试的代码:
constructor(io: any) {
this.server = io;
// *** bluebird is promises/A+ compliant, no need to convert it:
this.complete = db.Line.findAll().then(lines => {
// do some mapping to generate routes and cells
// *** return the promise!
// *** removed [] argument: not needed
return this.registerEndPoints(routes, cells);
}).catch(err => console.log(err))
}
// *** Remove the nsps parameter
registerEndPoints(routes: Array<string>, cells: Array<string>) {
// *** Create a promise-version of the `.on('connection', ...)` method
function nspConnect(nsp) {
return new Promise( resolve => nsp.on('connection', resolve) );
}
let that = this;
// *** Combine each route, cell, and nsp in one object, and put in array:
const data = routes.map( (route, i) => ({
nsp: that.server.of('/api/testNamespace/' + route),
route,
cell: cells[i]
}) );
// *** Map the array of objects to promises
const proms = data.map( ({nsp, route, cell}) =>
nspConnect(nsp).then(that.emitInitialPackage.bind(that, nsp, route, cell)) );
// *** Return a promise that resolves when all these have resolved
return Promise.all(proms);
}
不能将循环与异步代码一起使用。。。需要循环asynchronously@elclanrs好的,那么异步循环是什么样子的呢?这里有点不太清楚?this.server.of做什么/返回什么?构造函数中的单元格来自何处,registerEndPoints中的nsp是什么?为什么要等待nsp连接,然后关闭返回的套接字?为什么要这样做:Promise.resolvedb.Line.findAll?findAll重新运行一个承诺,或者它是同步的,或者它需要一个回调函数。在所有这些情况下,将其包装在承诺中都不会有任何好处。@Thomas this.server.of返回一个socketio命名空间。如上面注释的行中所述,单元格和路由是从行映射的。我将更新代码示例以更正此问题,但nsp是nsps的成员。不确定等待nsp连接是什么意思?findAll返回一个bluebird承诺,因此我使用promise.resolve将其转换为es6承诺您需要更新registerEndPoints以返回一个承诺,该承诺在所有emitInitialPackage调用完成时完成。然后将该承诺作为完整通话的一部分返回。这允许承诺流动或真正映射通过感谢你!您能解释一下nspConnect中的行吗nspConnect什么是resolve?nspConnect是一个返回承诺的函数。该承诺在调用对nsp.on的回调时解析。Promise构造函数总是将两个函数作为参数传递给提供给它的回调:resolve和reject。它们是承诺内部人员给出的句柄,用于解决承诺或拒绝承诺。我忽略了第二个。我提供resolve函数作为对nsp.on的回调,以便在建立连接时调用此解析。调用此resolve函数时,它将解析新承诺。但为什么要将resolve作为nsp.on的参数传入?因为on函数在完成它的任务时将调用第二个参数回调,当它执行时,我希望执行resolve,因为现在是解析承诺的时候了,所以这就是我将它传递给on的原因。好的,这个解决方案将使用什么包?
function nspConnect(nsp) {
return new Promise( resolve => {
console.log('creating promise');
return nsp.on('connection', socket => {
console.log('resolving');
resolve();
});
});
}