与承诺异步循环?
我有以下代码注册一系列socketio命名空间。逻辑的PArts取决于数据库调用(通过sequelize),因此我需要使用promise。我希望complete
的承诺能够在所有构造函数完成时都解决。我的问题是,complete
承诺在emitInitialPackage()
函数解决之前解决。与承诺异步循环?
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
之前complete
做出决议已经完成?
等待所有操作完成在registerEndPoints
,此方法应该返回Promise
可以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
参数传递的参数[]
没有任何用途作为参数,因此您不妨一起跳过该参数; -
.on('connection', ...)
函数应该打包以返回一个承诺; -
for
循环应创建这些承诺,然后将它们传递给Promise.all
以获得最终结果。可以使用map
; - 这是不是一个很好的结构,你有三个数组(
routes
,cells
和nsps
)在相同的索引有相关的数据。更好的结构是你有一个对象数组,其中每个对象都有三个属性:(route
,cell
和nsp
); - 蓝鸟承诺/ A +兼容,所以不应该将蓝鸟承诺转换为原生JS承诺。
下面是一些未经测试的代码:
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);
}
有一些调试的可能性,你可以展开nspConnect
功能:
function nspConnect(nsp) {
return new Promise(resolve => {
console.log('creating promise');
return nsp.on('connection', socket => {
console.log('resolving');
resolve();
});
});
}
谢谢你!你能解释'nspConnect(nsp)'什么是'resolve'这一行吗? –
'nspConnect'是一个返回承诺的函数。该承诺解决了何时调用'nsp.on'的回调。 'Promise'构造函数总是将两个函数作为参数传递给提供给它的回调函数:'resolve'和'reject'。它们是由承诺内部人员提供的解决承诺或拒绝承诺的句柄。我忽略了第二个。我提供'resolve'函数作为'nsp.on'的回调函数,以便在建立连接时调用这个'resolve'。当这个'resolve'函数被调用时,它将解析'new Promise'。 – trincot
但是为什么''resolve'作为'nsp.on(...'? –
不能使用循环与这样的异步代码。 ..需要循环异步 – elclanrs
@elclanrs好吧,那么异步循环会是什么样子? –
这里有一点不太清楚吗? 'this.server.of()'做/返回什么? 'cell'来自构造函数,'registerEndPoints'中的'nsp'是什么?你为什么要等nsp连接,然后关闭套接字返回?你为什么这样做:'Promise.resolve(db.Line.findAll())'? findAll()会回复一个承诺,或者它是同步的,或者它期望一个回调函数。在所有这些情况下,你都可以通过将其包装在承诺中获得任何收益。 – Thomas