繁体   English   中英

ES6承诺,只有先前的承诺被拒绝,同时保留拒绝理由,才能将承诺链接起来

[英]ES6 promises, chaining promises only if previous promises were rejected, while keeping rejection reasons

我正在构建一个身份验证API,尝试对不同的身份验证方法进行身份验证,直到成功(如Spring Security)。

每个身份验证方法都会返回一个promise,如果身份验证成功就会完成,如果身份验证失败则会被拒绝。

要尝试验证用户,我需要按顺序调用身份验证方法:

  • 如果第一个身份验证方法成功,则对用户进行身份验证,并且我不希望调用其他身份验证方法。
  • 如果第一种身份验证方法失败,我需要尝试第二种身份验证方法。 等等...
  • 如果没有一种身份验证方法成功,我需要拒绝身份验证,并且可能知道每次身份验证失败的原因。
  • 如果身份验证成功,我需要获取一个值(身份验证对象)。

这个过程几乎是承诺库调用.any (或.some ),除了我不想执行每个promise(因此尝试每个身份验证方法,这会导致不必要的工作量)。 我想在以前的失败时尝试下一个身份验证方法

问题1:Promise / A +兼容库中是否有可用的功能? 问题2:我一直在考虑以下方式(参见下面的代码),有没有更好的方法?

// Defining some promise factories
var promiseFactory1 = {
    buildPromise: function() {
        return new Promise((resolve, reject) => {
            console.log('trying p1...');
            // resolve('p1 success');
            reject('p1 failure');
        })
    }
};

var promiseFactory2 = {
    buildPromise: function() {
        return new Promise((resolve, reject) => {
            console.log('trying p2...');
            // resolve('p2 success');
            reject('p2 failure');
        })
    }
};

var promiseFactory3 = {
    buildPromise: function() {
        return new Promise((resolve, reject) => {
            console.log('trying p3...');
            resolve('p3 success');
            // reject('p3 failure');
        })
    }
};

// Building the promise
let promisesFactory = [promiseFactory1, promiseFactory2, promiseFactory3];
let rejections = [];

var reducedPromise = promisesFactory.reduce(function(promise, nextFactory) {
    if (promise === null) return nextFactory.buildPromise();

    return promise.catch(err => {
        rejections.push(err);
        return nextFactory.buildPromise();
    });
}, null);

reducedPromise
    .catch(err => {
        rejections.push(err); // catching the last rejection
    })
    .then(success => {
        if(rejections.length == promisesFactory.length) {
            console.log(rejections);
            // TODO return Promise.reject(new SomeCustomError());
        } else {
            console.log(success);
            // TODO return Promise.resolve(success);
        }
    });

我相信你可以这样做(其中auth1auth2auth3是返回promises的auth函数):

auth1(/*args*/)
    .catch(failed => auth2(/*args*/))
    .catch(failed => auth3(/*args*/))
    .then(result => {
      console.log("Success:" + result);
      return result;
    })
    .catch(failed => {
      console.log("Failure:" + failed);
    });

因为我们没有then回调,分辨率值传播到最终then (就像具有.then(result => result) ); 但我们从catch回调中返回新的promise,触发下一个身份验证方法。

then在最后获得的第一个随后的AUTH方法的分辨率值; 上面的最后一个catch只是得到了最后一个失败的auth方法( auth3 )的拒绝原因。

生活在巴贝尔的REPL上

如果您需要所有失败的原因,您可以将它们保存在一个数组中:

let failures = [];
auth1(/*args*/)
    .catch(failed => {failures.push(failed); return auth2(/*args*/);})
    .catch(failed => {failures.push(failed); return auth3(/*args*/);})
    .then(result => {
      console.log("Success: " + result + " (failed: " + failures.join(", ") + ")");
      return result;
    })
    .catch(failed => {
      failures.push(failed);
      console.log("Failures: " + failures.join(", "));
    });

实时复制

如果您的auth方法本身在一个数组中,您可以在循环中执行上述操作:

let auths = [auth1.bind(null, /*args*/), auth2.bind(null, /*args*/), auth3.bind(null, /*args*/)];
return auths.reduce((p, auth) => p.catch(failed => auth()), Promise.reject())
    .then(result => {
      console.log("Success: " + result);
      return result;
    })
    .catch(failed => {
      console.log("Failed: " + failed);
    });

实时复制

暂无
暂无

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

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