Javascript:如何使用承诺迭代数组? [英] Javascript: How to iterate on array using promises?

查看:21
本文介绍了Javascript:如何使用承诺迭代数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

现场演示

给定以下函数:

function isGood(number) {var defer = $q.defer();$超时(功能(){如果(<数字上的某些条件>){defer.resolve();} 别的 {defer.reject();}}, 100);返回 defer.promise;}

和一组数字(例如 [3, 9, 17, 26, 89]),我想找到 第一个好"数字.我希望能够做到这一点:

var arr = [3, 9, 17, 26, 89];findGoodNumber(arr).then(function(goodNumber) {console.log('找到好号码:' + goodNumber);}, 功能() {console.log('没有找到好的数字');});

这是一种可能的递归版本来实现这一点:DEMO

function findGoodNumber(numbers) {var defer = $q.defer();if (numbers.length === 0) {defer.reject();} 别的 {var num = numbers.shift();isGood(num).then(function() {defer.resolve(num);}, 功能() {findGoodNumber(numbers).then(defer.resolve, defer.reject)});}返回 defer.promise;}

我想知道是否有更好的(也许是非递归的)方法?

解决方案

不知道有没有更好的方法?

是的.避免延迟反模式

function isGood(number) {返回 $timeout(function() {如果(<数字上的某些条件>){退货号码;//用数字解析,简化下面的代码} 别的 {throw new Error("...");}}, 100);}函数 findGoodNumber(numbers) {if (numbers.length === 0) {返回 $q.reject();} 别的 {返回 isGood(numbers.shift()).catch(function() {返回 findGoodNumber(numbers);});}}

<块引用>

也许是非递归的?

您可以制定一个循环来链接许多 then 调用,但是在这里递归绝对没问题.如果你真的想要循环,它可能看起来像这样:

function findGoodNumber(numbers) {返回 numbers.reduce(function(previousFinds, num) {返回 previousFinds.catch(function() {返回 isGood(num);});}, $q.reject());}

然而,这效率较低,因为它总是查看所有数字.递归"版本会懒惰地评估它,如果当前数字不好,只会再做一次迭代.

<块引用>

也许更快?

您可以并行触发所有 isGood 检查,并等待第一个满足的返回.根据 isGood 的实际作用以及可并行化的程度,这可能更好".不过,它可能会做很多不必要的工作;您可能想要使用支持取消的承诺库.

一个使用 Bluebird 库的例子,它有一个 any 辅助函数专用于此任务:

function findGoodNumber(numbers) {返回 Bluebird.any(numbers.map(isGood))}

LIVE DEMO

Given the following function:

function isGood(number) {
  var defer = $q.defer();

  $timeout(function() {
    if (<some condition on number>) {
      defer.resolve();
    } else {
      defer.reject();
    }
  }, 100);

  return defer.promise;
}

and an array of numbers (e.g. [3, 9, 17, 26, 89]), I would like to find the first "good" number. I would like to be able to do this:

var arr = [3, 9, 17, 26, 89];

findGoodNumber(arr).then(function(goodNumber) {
  console.log('Good number found: ' + goodNumber);
}, function() {
  console.log('No good numbers found');
});

Here is one possible recursive version to implement this: DEMO

function findGoodNumber(numbers) {
  var defer = $q.defer();

  if (numbers.length === 0) {
    defer.reject();
  } else {
    var num = numbers.shift();

    isGood(num).then(function() {
      defer.resolve(num);
    }, function() {
      findGoodNumber(numbers).then(defer.resolve, defer.reject)
    });
  }

  return defer.promise;
}

I wonder if there is a better (maybe non-recursive) way?

解决方案

I wonder if there is a better way?

Yes. Avoid the deferred antipattern!

function isGood(number) {
  return $timeout(function() {
    if (<some condition on number>) {
      return number; // Resolve with the number, simplifies code below
    } else {
      throw new Error("…");
    }
  }, 100);
}
function findGoodNumber(numbers) {
  if (numbers.length === 0) {
    return $q.reject();
  } else {
    return isGood(numbers.shift()).catch(function() {
      return findGoodNumber(numbers);
    });
  }
}

maybe non-recursive?

You can formulate a loop that chains lots of then calls, however recursion is absolutely fine here. If you really wanted the loop, it might look like this:

function findGoodNumber(numbers) {
  return numbers.reduce(function(previousFinds, num) {
    return previousFinds.catch(function() {
      return isGood(num);
    });
  }, $q.reject());
}

This is however less efficient, as it always looks at all numbers. The "recursive" version will evaluate it lazily, and only do another iteration if the current number was not good.

maybe faster?

You can fire all isGood checks in parallel, and wait for the first fulfilled to return. Depending on what isGood actually does and how well that is parallelizable, this might be "better". It potentially does a lot of unnecessary work, though; you may want to use a promise library that supports cancellation.

An example using the Bluebird library, which has a any helper function dedicated to this task:

function findGoodNumber(numbers) {
  return Bluebird.any(numbers.map(isGood))
}

这篇关于Javascript:如何使用承诺迭代数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆