简体   繁体   English

While 循环中的承诺,其中 while 的条件基于承诺的结果

[英]Promises in a While Loop where condition of while is based on result of the promise

I need to do an indeterminate loop where the condition of the loop will be based on the response from a promise within the loop that gets some data from a database.我需要做一个不确定循环,其中循环的条件将基于循环中从数据库中获取一些数据的承诺的响应。 The loop should be done from within a promise that then returns the total list of records pulled from the database.循环应该在一个承诺内完成,然后返回从数据库中提取的记录的总列表。 This is somewhat simplified from the real world example, but have tried to provide some basic code to demonstrate what I want essentially to do.这从现实世界的例子中得到了一些简化,但试图提供一些基本的代码来演示我想要做的事情。

The call to getLinkedEntities passes in an entity and based on a linked entity id begins the loop where linked entities are returned and then returned from the original promise.对 getLinkedEntities 的调用传入一个实体,并基于链接的实体 id 开始循环,在该循环中返回链接的实体,然后从原始承诺返回。

The problem I have is that because of the asynchronous nature of promises the moment getElement is called within the while loop it never resolves because the function continues and gets stuck in continuous loop.我遇到的问题是,由于承诺的异步性质,在 while 循环中调用 getElement 的那一刻它永远不会解决,因为函数继续并陷入连续循环。

Hopefully this code describes well enough what I am trying to do, ie end up with an array of linked entities, but how can it be done in a synchronous way that allows all promises to 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
    });

Without using async / await , what you can do is create an inner function, that calls itself.在不使用async / await ,您可以做的是创建一个调用自身的内部函数。

eg.例如。

  ...
  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();
}

Basically this just keeps calling getNext until stopLoop is set, and then resolves linkedEntities , if not it calls getNext again.基本上,这只是不断呼吁getNext直到stopLoop设置,然后解决linkedEntities ,如果没有它调用getNext一次。 IOW: exactly what your while loop is doing. IOW:正是您的 while 循环在做什么。

Below is a working snippet that uses this idea, instead of getElement , I've replaced with a sleep promise.下面是一个使用这个想法的工作片段,而不是getElement ,我已经用睡眠承诺代替了。 Basically fill's an array waiting 500ms between each array push.基本上填充的数组在每次数组推送之间等待 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(',')); });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM