Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/38.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在承诺返回函数中找到第一个成功_Javascript_Node.js_Asynchronous_Promise_Short Circuiting - Fatal编程技术网

Javascript 在承诺返回函数中找到第一个成功

Javascript 在承诺返回函数中找到第一个成功,javascript,node.js,asynchronous,promise,short-circuiting,Javascript,Node.js,Asynchronous,Promise,Short Circuiting,给定一些函数,返回承诺: function foo(arg) { return new Promise(function(resolve, reject) { if (stuff(arg)) { resolve('result from foo'); } else { resolve(null); } }); ); // ... maybe more of these functions ... function bar(arg) {

给定一些函数,返回承诺:

function foo(arg) {
  return new Promise(function(resolve, reject) {
    if (stuff(arg)) {
      resolve('result from foo');
    } else {
      resolve(null);
    }
  });
);

// ... maybe more of these functions ...

function bar(arg) {
  return new Promise(function(resolve, reject) {
    if (otherStuff(arg)) {
      resolve('result from bar');
    } else {
      resolve(null);
    }
  });
);
我们如何以串行方式迭代函数,在第一个函数返回非空值后短路?

[
  foo,
  // ...
  bar
].firstWithArg('some arg')
  .then(function(result) {
    // result: 'result from ___', or `null`
  });
基本上,期望的行为是:

new Promise(function(resolve, reject){
  foo('some-arg')
    .then(function(result) {
      if (result) {
        resolve(result);
      } else {

        // ...

          bar('some-arg')
            .then(function(result) {
              if (result) {
                resolve(result);
              } else {
                resolve(null); // no functions left
              }
            })
      }
    });
});

Promise.race()不能使用,因为函数不能全部启动。它们必须连续执行,在第一次成功后停止。

我不认为有任何预先构建的内容。您可以创建自己的,无需太多工作。假设您有一个函数数组,在调用时返回承诺。然后,您可以迭代该数组,并在得到喜欢的结果时停止。当序列中的承诺被拒绝时,不清楚您想要做什么-此实现继续到下一个函数,但您可以为该情况编写任何您想要的行为:

function iterateUntilGood(list, args) {
    var cntr = 0;

    return new Promise(function(resolve, reject) {
        function next() {
            if (list.length > cntr) {
                list[cntr++].apply(null, args).then(function(result) {
                    // check the result here
                    if (some condition) {
                        resolve(result);
                    } else {
                        next();
                    }
                }, next);
            } else {
                reject("No function succeeded");
            }
        }
        next();
    });
}

// usage
iterateUntilGood([fn1, fn2, fn3, fn4], [arg1, arg2]).then(function(result) {
    // got result here
}, function(err) {
    // handle error here
});

工作演示:

您说过您的第一个问题实际上只是第二个问题的设置,这才是真正的问题

所以我想你的问题是:如何执行一系列函数,当第一个函数解析为非null值时,它们会串行地返回承诺,短路

我可能不会,我会使用
拒绝
而不是
解析(null)
(但在一篇评论中,您已经澄清了您想要
解析(null)
,我明白您的观点;我将在下面介绍这一点):

function-otherStuff(arg){
返回arg==2;
}
函数填充(arg){
返回arg==“c”;
}
函数foo(arg){
log(“foo:”,arg);
返回新承诺(功能(解决、拒绝){
if(填充(arg)){
log(“foo:,arg,“解析”);
解决(“来自foo的结果”);
}否则{
log(“foo:,arg,“拒绝”);
拒绝();//foo(“b”))
.catch(()=>bar(2))
.catch(()=>foo(“c”))
.catch(()=>bar(3))
.然后(值=>{
console.log(“完成”,值);

});
多亏了@T.J.Crowder和@jfriend00的回答

TL;DR:
目标:迭代返回承诺的函数,直到我们成功地用一个值
解析
,然后我们短路。我们不想
承诺。竞赛
,而是串行运行函数

有关完整的工作示例,请参见此代码段:

/*定义返回承诺履行以下合同的函数:
*开关(状态){
*成功案例:
*决心(结果);
*中断;
*案例失败:
*解析(空);
*中断;
*案例错误:
*拒绝(错误);
*   }
*/
常量函数=[
arg=>新承诺((解决)=>{
console.log('对照检查',arg);
如果(arg=='a'){
决议(“A”);
}否则{
解决();
}
}),
arg=>新承诺((解决)=>{
log('对照'arg'检查b');
如果(arg=='b'){
决议(“B”);
}否则{
解决();
}
}),
//故意省略处理“c”
arg=>新承诺((解决、拒绝)=>{
console.log('对照检查数据',arg);
如果(arg=='d'){
log(“模拟错误”);
拒绝(新错误('D'));
}否则{
解决();
}
}),
arg=>新承诺((解决)=>{
console.log('对照检查e',arg);
如果(arg=='e'){
决议(‘E’);
}否则{
解决();
}
})
];
/*连续调用具有给定参数的函数,直到解析出一个值,
*然后我们短路。
*/
函数委托(arg){
console.log('\n为''arg'删除);
减少(
//请注意,此空比较总是发生N次,
//其中N是函数数
//(除非其中一个函数拒绝)
(p,fn)=>p.then(r=>r?r:fn(arg)),
Promise.resolve(null)
).然后(值=>{
log('Done:',值);
})
.catch(错误=>{
console.log('Error:',Error);
});
}
//通过委托函数运行示例输入
[a',b',c',d',e']{
setTimeout(delegate.bind(null,e),i*100);//延迟,用于打印

});
每个问题问一个问题。你上面的问题有完全不同的用例和解决方案,你的第一个问题与你的问题标题无关。@T.J.Crowder我真的把第一个问题作为第二个问题的类比。@jfriend00我看了Promise.race(),但它不适合我的用例。我需要串行执行函数,并且短路,而不是全部启动,然后得到第一个完成的结果。@bosticko:上面还不清楚。我建议澄清一下。如果有大量函数,有没有一种方法可以通过编程方式链接调用?@bosticko-是的,在我的答案,你似乎没有注意到。@bosticko:你是说如果你有一个函数数组要调用吗?@t.J.Crowder,确切地说,是一个函数数组。@bosticko:是的。甚至还有一个习惯用法。我已经把它添加到了答案中。所以你在函数列表中递归迭代,直到找到想要的结果为止?@bosticko-是的,基本上是这样。这不是常规递归,因为它们是异步操作,所以没有堆栈构建。但是,它使用一个公共函数来执行迭代的下一步,直到找到喜欢的结果并希望停止迭代为止。这是序列化异步操作的一个公共模式。您可以执行下一个异步操作在完成之前的一个过程中进行操作。@bosticko-我在我的解决方案中添加了数组中函数的参数。如果您有任何反馈,我很高兴在代码片段中看到这一点,但我相信您。:-@T.J.Crowder-我添加了一个jsFiddle.@T.J.Crowder我已经将您的答案改编为我正在寻找的内容。谢谢您的帮助。
function foo(arg) {
  return new Promise(function(resolve, reject) {
    if (stuff(arg)) {
      resolve('result from foo');
    } else {
      reject();          // <=== Note
    }
  });
}

// ... maybe more of these functions ...

function bar(arg) {
  return new Promise(function(resolve, reject) {
    if (otherStuff(arg)) {
      resolve('result from bar');
    } else {
      reject();          // <=== Note
    }
  });
}
foo("a")
  .catch(() => bar(1))
  .catch(() => foo("b"))
  .catch(() => bar(2))
  .catch(() => foo("c"))
  .catch(() => bar(3))
  .then(value => {
    console.log("Done", value);
  });
const arg = 'some common arg';
const functions = [
  arg => new Promise((resolve, reject) => {
    /* Does some work, then calls:
     *   resolve(something) if success
     *   resolve(null)      if failure
     *   reject(error)      if error
     */
  })
]

functions.reduce(
  (prev, fn) => prev.then(res => res ? res : fn(arg)),
  Promise.resolve(null) // base case
) // returns promise which honours same contract as functions
  //   (resolves with something or null, or rejects with error)