当前位置: 首页 > 知识库问答 >
问题:

适当的时()循环蓝鸟promise(没有递归?)

羊慈
2023-03-14

我已经用蓝鸟学习promise两周了。我已经基本理解了它们,但是我去解决了一些相关的问题,似乎我的知识已经崩溃了。我试着做这个简单的代码:

var someGlobal = true;

whilePromsie(function() { 
   return someGlobal;
}, function(result) { // possibly even use return value of 1st parm?
 // keep running this promise code
 return new Promise(....).then(....);
});

作为一个具体例子:

// This is some very contrived functionality, but let's pretend this is 
// doing something external: ajax call, db call, filesystem call, etc.
// Simply return a number between  0-999 after a 0-999 millisecond
// fake delay.
function getNextItem() { 
    return new Promise.delay(Math.random()*1000).then(function() {
        Promise.cast(Math.floor(Math.random() * 1000));
    });
}

promiseWhile(function() {
    // this will never return false in my example so run forever
    return getNextItem() !== false;
}, // how to have result == return value of getNextItem()? 
function(result) {
    result.then(function(x) { 
        // do some work ... 
    }).catch(function(err) { 
        console.warn("A nasty error occured!: ", err);
    });
}).then(function(result) { 
    console.log("The while finally ended!");
});

现在我已经做了作业!还有同样的问题,但在这里面向Q. js:

为promise编写循环的正确方法。

但是接受的答案,以及其他答案:

  • 面向Q.js或RSVP
  • 针对bluebird的唯一答案是使用递归。这些看起来很可能会在无限循环(比如我的循环)中导致巨大的堆栈溢出?或者,充其量只能是非常低效的,并且可以免费创建一个非常大的堆栈?如果我错了,那好吧!让我知道。
  • 不允许您使用条件的结果。虽然这不是要求——我只是好奇这是否可能。我正在编写的代码,一个用例需要它,另一个不需要

现在,有一个关于使用此async()方法的RSVP的答案。真正让我困惑的是bluebird文档,我甚至在存储库中看到了Promise.async()调用的代码,但在我最新的bluebird副本中没有看到。它只是在git存储库中还是什么?

共有1个答案

南宫才艺
2023-03-14

你想做什么还不是100%清楚,但我会写一个答案,做你提到的以下事情:

  1. 循环,直到代码中的某些条件得到满足
  2. 允许您在循环迭代之间使用延迟
  3. 允许您获取并处理最终结果
  4. 与Bluebird一起使用(我将按照ES6 promise标准编写代码,该标准将与Bluebird或native promises一起使用)
  5. 没有堆叠

首先,假设您有一个异步函数,它返回一个promise,其结果用于确定是否继续循环。

function getNextItem() {
   return new Promise.delay(Math.random()*1000).then(function() {
        return(Math.floor(Math.random() * 1000));
   });
}

现在,您想要循环,直到返回的值满足某个条件

function processLoop(delay) {
    return new Promise(function(resolve, reject) {
        var results = [];

        function next() {
            getNextItem().then(function(val) {
                // add to result array
                results.push(val);
                if (val < 100) {
                    // found a val < 100, so be done with the loop
                    resolve(results);
                } else {
                    // run another iteration of the loop after delay
                    setTimeout(next, delay);
                }
            }, reject);
        }
        // start first iteration of the loop
        next();
    });
}

processLoop(100).then(function(results) {
   // process results here
}, function(err) {
   // error here
});

如果希望使其更通用,以便传入函数和比较,可以执行以下操作:

function processLoop(mainFn, compareFn, delay) {
    return new Promise(function(resolve, reject) {
        var results = [];

        function next() {
            mainFn().then(function(val) {
                // add to result array
                results.push(val);
                if (compareFn(val))
                    // found a val < 100, so be done with the loop
                    resolve(results);
                } else {
                    // run another iteration of the loop after delay
                    if (delay) {
                        setTimeout(next, delay);
                    } else {
                        next();
                    }
                }
            }, reject);
        }
        // start first iteration of the loop
        next();
    });
}

processLoop(getNextItem, function(val) {
    return val < 100;
}, 100).then(function(results) {
   // process results here
}, function(err) {
   // error here
});

您尝试这样的结构:

return getNextItem() !== false;

无法工作,因为getNextItem()返回的promise总是!==false因为promise是一个无法工作的对象。如果要测试promise,必须使用.then()获取其值,并且必须异步进行比较,这样就不能直接返回这样的值。

注意:虽然这些实现使用一个调用自身的函数,但这不会导致堆栈构建,因为它们是异步调用自己的。这意味着在函数再次调用自身之前,堆栈已经完全展开,因此没有堆栈构建。.then()处理程序的情况始终如此,因为Promise规范要求在堆栈返回到“平台代码”之前不调用.then()处理程序,这意味着在调用.then()处理程序之前,它已解开所有常规的“用户代码”。

在ES7中使用asyncwait

在ES7中,您可以使用异步和等待来“暂停”循环。这可以使这种类型的迭代更加简单。这在结构上看起来更像一个典型的同步回路。它使用wait来等待promise,因为函数被声明为async,所以它总是返回一个promise:

function delay(t) {
    return new Promise(resolve => {
        setTimeout(resolve, t);
    });
}

async function processLoop(mainFn, compareFn, timeDelay) {
    var results = [];

    // loop until condition is met
    while (true) {
        let val = await mainFn();
        results.push(val);
        if (compareFn(val)) {
            return results;
        } else {
            if (timeDelay) {
                await delay(timeDelay);
            }
        }
    }
}

processLoop(getNextItem, function(val) {
    return val < 100;
}, 100).then(function(results) {
   // process results here
}, function(err) {
   // error here
});
 类似资料:
  • 问题内容: 什么是处理这种情况的最佳方法。我处于受控环境中,所以我不想崩溃。 从setTimeout内抛出时,我们将始终获得: 如果抛出发生在setTimeout之前,那么bluebirds catch将捕获它: 结果是: 很棒-但是如何在节点或浏览器中处理这种性质的恶意异步回调。 问题答案: 承诺不是域,它们不会捕获异步回调中的异常。你就是做不到。 然而诺言来捕捉从内抛出的异常/ / 构造函数的

  • 这是我的代码的简短版本。 两个条件都调用。有没有办法避免其他情况?我可以做,但我正在寻找一个非阻塞的解决方案。

  • 我正在尝试制作一个闰年计算器,它还可以告诉你是无意中输入了字符串还是双精度而不是整数。我想让这个程序反复运行“错误。请输入一个不带小数的数字:”直到用户输入一个整数。然而,目前,对于第一个try-catch块,如果我输入了两种错误的输入类型,它会给我以下错误消息: 第二个至少稍微好一点,它不断重复我输入的最后一个整数的结果(年份“是闰年/不是闰年”),但至少它永远重复,不像第一个。 所有我想要的错

  • 我这里有个情况。我有一个promise函数,它以这种方式运行 > 我的promise函数get问题调用另一个promise函数DB.查询,它从mysqlite数据库获取结果(Main_Question)。 当我得到DB查询的结果后,我调用get答案函数,它也是一个获取该问题答案的promise函数 现在主问题可能有N个子问题。所以我再次运行DB。获取所有子问题的查询。 现在,我必须找到这些问题的答

  • 我尝试将我的SSL证书添加到JVM的密钥存储库中,我甚至尝试用这段代码接受每一个证书(这违背了我所知道的SSL的目的 我被难住了,任何帮助都将非常感谢!

  • 问题内容: 我正在使用bluebird,方法 getAll 和 update return promises。我如何说“等到两个承诺返回,然后更新currentProduct值”?我对JS很陌生… 问题答案: 如果可以使用/,这将很简单。 或者,如果您只能使用简单的承诺,则可以遍历所有产品,并将每个承诺置于最后一个循环中。这样,仅当前一个问题解决时,它才会前进到下一个问题(即使它将首先迭代整个循环