While 循环中的承诺,其中 while 条件基于承诺的结果
Promises in a While Loop where condition of while is based on result of the promise
我需要做一个不确定的循环,其中循环的条件将基于循环内从数据库获取一些数据的承诺的响应。循环应该在承诺中完成,然后 returns 从数据库中提取记录的总列表。这在现实世界的示例中有所简化,但已尝试提供一些基本代码来演示我本质上想要做什么。
对 getLinkedEntities 的调用传入一个实体,并基于链接的实体 ID 开始循环,其中链接的实体被 returned,然后从原始 promise returned。
我遇到的问题是,由于承诺的异步性质,在 while 循环中调用 getElement 的那一刻它永远不会解决,因为函数继续并卡在连续循环中。
希望这段代码足够好地描述了我正在尝试做的事情,即最终得到一组链接实体,但是如何以允许所有承诺的同步方式完成return?
function getLinkedEntities(startEntity) {
return new Promise(function (resolve, reject) {
var linkedEntities = [];
var entityId = startEntity.id;
var someOtherId = startEntity.linkedentityid;
var stopLoop = false;
do {
getElement(someOtherId).then(function (entity) {
linkedEntities.push(entity)
entityId = entity.id;
someOtherId = entity.linkedentityid;
stopLoop = entity.linkedentityid === null ? 1 : 0;
});
}
while (!stopLoop);
resolve(linkedEntities);
});
}
function getElement(id) {
return new Promise(function (resolve, reject) {
// go to database and get an entity
resolve(entity);
});
}
getLinkedEntities(someEntity).then(function (response) {
// do somethign with linkedEntities
});
在不使用 async / await
的情况下,您可以创建一个内部函数来调用自身。
例如
...
function getNext() {
return getElement(someOtherId).then(function (entity) {
linkedEntities.push(entity)
entityId = entity.id;
someOtherId = entity.linkedentityid;
stopLoop = entity.linkedentityid === null ? 1 : 0;
if (stopLoop) return resolve(linkedEntities);
else return getNext();
});
}
//boot strap the loop
return getNext();
}
基本上这只是一直调用 getNext
直到 stopLoop
被设置,然后解析 linkedEntities
,如果没有它再次调用 getNext
。 IOW:正是你的 while 循环在做什么。
下面是一个使用这个想法的工作片段,而不是 getElement
,我已经用睡眠承诺代替了。基本上填充一个数组,在每次数组推送之间等待 500 毫秒。
function sleep(ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
}
function test() {
var ret = [];
function getNext() {
return sleep(500).then(function () {
if (ret.length >= 10) {
return ret;
} else {
console.log('tick: ' + ret.length);
ret.push(ret.length + 1);
return getNext();
}
});
}
return getNext();
}
test().then(function (r) {
console.log('Resolved with ->');
console.log(r.join(','));
});
我需要做一个不确定的循环,其中循环的条件将基于循环内从数据库获取一些数据的承诺的响应。循环应该在承诺中完成,然后 returns 从数据库中提取记录的总列表。这在现实世界的示例中有所简化,但已尝试提供一些基本代码来演示我本质上想要做什么。
对 getLinkedEntities 的调用传入一个实体,并基于链接的实体 ID 开始循环,其中链接的实体被 returned,然后从原始 promise returned。
我遇到的问题是,由于承诺的异步性质,在 while 循环中调用 getElement 的那一刻它永远不会解决,因为函数继续并卡在连续循环中。
希望这段代码足够好地描述了我正在尝试做的事情,即最终得到一组链接实体,但是如何以允许所有承诺的同步方式完成return?
function getLinkedEntities(startEntity) {
return new Promise(function (resolve, reject) {
var linkedEntities = [];
var entityId = startEntity.id;
var someOtherId = startEntity.linkedentityid;
var stopLoop = false;
do {
getElement(someOtherId).then(function (entity) {
linkedEntities.push(entity)
entityId = entity.id;
someOtherId = entity.linkedentityid;
stopLoop = entity.linkedentityid === null ? 1 : 0;
});
}
while (!stopLoop);
resolve(linkedEntities);
});
}
function getElement(id) {
return new Promise(function (resolve, reject) {
// go to database and get an entity
resolve(entity);
});
}
getLinkedEntities(someEntity).then(function (response) {
// do somethign with linkedEntities
});
在不使用 async / await
的情况下,您可以创建一个内部函数来调用自身。
例如
...
function getNext() {
return getElement(someOtherId).then(function (entity) {
linkedEntities.push(entity)
entityId = entity.id;
someOtherId = entity.linkedentityid;
stopLoop = entity.linkedentityid === null ? 1 : 0;
if (stopLoop) return resolve(linkedEntities);
else return getNext();
});
}
//boot strap the loop
return getNext();
}
基本上这只是一直调用 getNext
直到 stopLoop
被设置,然后解析 linkedEntities
,如果没有它再次调用 getNext
。 IOW:正是你的 while 循环在做什么。
下面是一个使用这个想法的工作片段,而不是 getElement
,我已经用睡眠承诺代替了。基本上填充一个数组,在每次数组推送之间等待 500 毫秒。
function sleep(ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
}
function test() {
var ret = [];
function getNext() {
return sleep(500).then(function () {
if (ret.length >= 10) {
return ret;
} else {
console.log('tick: ' + ret.length);
ret.push(ret.length + 1);
return getNext();
}
});
}
return getNext();
}
test().then(function (r) {
console.log('Resolved with ->');
console.log(r.join(','));
});