简体   繁体   English

ECMAScript 2015顺序调用Promises

[英]ECMAScript 2015 call Promises sequentially

I am trying to rewrite a synchronous junction to work with promises, and am a bit stuck with it. 我正在尝试重写同步联结以与Promise一起使用,并且对此有些困惑。 I have a function that call different routines A , B , and C , depending on arguments and results: 我有一个函数,根据参数和结果调用不同的例程ABC

const worker = (v, r, ok, er)=>{
  if(v > 10) {
    ok(r)
  } else {
    er(r)
  }
};

const A = v=>{let r = null; worker(v, 'a', _r=>r=_r, ()=>{});return r};
const B = v=>{let r = null; worker(v, 'b', _r=>r=_r, ()=>{});return r};
const C = v=>{let r = null; worker(v, 'c', _r=>r=_r, ()=>{});return r};

const mainSync = (obj)=>{
  let result = null;
  if(obj.a) {
    result = A(obj.a);
  }
  if (!result && obj.b) {
    result = B(obj.b);
  }
  if (!result && obj.c) {
    result = C(obj.c);
  }
  return result;
}

which works fine https://repl.it/JcjE/0 with synchronous A , B , and C : 使用同步ABC可以正常工作https://repl.it/JcjE/0

mainSync({a:4}) === null;
mainSync({a:4, b:14}) === 'b';
mainSync({a:14, b:14}) === 'a';
mainSync({b:4, c:14}) === 'c';
// etc

Now A , B , and C become Promises: 现在, ABC成为Promises:

const worker = (v, r, ok, er)=>{
  if(v > 10) {
    ok(r)
  } else {
    er(r)
  }
};

const A = v=>new Promise((ok, er)=>worker(v, 'a', ok, er));
const B = v=>new Promise((ok, er)=>worker(v, 'b', ok, er));
const C = v=>new Promise((ok, er)=>worker(v, 'c', ok, er));

and I am not quite sure how to handle it: 而且我不太确定如何处理它:

const mainAsync = (obj)=>{
    // what todo here?
}

I am happy with mainAsync to return Promise itself, like 我对mainAsync很高兴返回Promise本身,例如

mainAsync({a:4}).then(r=>r === null);
mainAsync({a:4, b:14}).then(r=>r === 'b');
mainAsync({a:14, b:14}).then(r=>r === 'a');
mainAsync({b:4, c:14}).then(r=>r === 'c');

The problem is that call to B depends on result of A , and call to C depends on results of both A and B , and no async/await available yet. 问题是对B调用取决于A结果,对C调用取决于AB结果,并且还没有async/await可用。

I have tried my naive approach https://repl.it/Jcjw/0 but it is terrible and doesn't quite work on real life scale. 我已经尝试过我的幼稚方法https://repl.it/Jcjw/0,但是它很糟糕,并且无法在现实生活中发挥作用。

PS: I am looking for vanilla javascript if possible, and am aware about similar questions like PS:如果可能,我正在寻找香草javascript,并且知道类似的问题,例如

etc, but couldn't figure out how to apply them to my case. 等等,但不知道如何将它们应用于我的案子。

Depending on which type of browsers you are trying to target, you can use the async/await features that are in chrome for sure. 根据要尝试定位的浏览器类型,可以确定使用chrome中的async/await功能。

 function promiseA(){return Promise.resolve(20)} function promiseB(arg){return Promise.resolve(arg * 2)} function promiseC(arg){return Promise.resolve(arg + 10)} (async function(){ let a = await promiseA(); console.log(a) let b = await promiseB(a); console.log(b) let c = await promiseC(b); console.log(c) })(); 

To call the promises in sequence, you can call the next one in the .then callback. 要依次调用promise,可以在.then回调中调用下一个。 Your conditions ( if (!result && ...) ) translate pretty easily: 您的条件( if (!result && ...) )很容易翻译:

function mainAsync(obj) {
  return (obj.a ? A(obj.a) : Promise.resolve())
    .then(result => !result && obj.b ? B(obj.b) : result)
    .then(result => !result && obj.c ? C(obj.c) : result);
}

If you need to do this for many properties, then you can avoid repeating yourself too much by using a lookup table and a loop ( Array#reduce in this case): 如果您需要对许多属性执行此操作,则可以通过使用查找表和循环(在这种情况下为Array#reduce )来避免重复太多:

const funcs = {
  a: A,
  b: B,
  c: C,
};
const props = ['a', 'b', 'c'];

function mainAsync(obj) {
  return props.reduce(
    (promise, prop) => promise.then(
      result => !result && obj[prop] ? funcs[prop](obj[prop]) : result
    ).catch(() => Promise.resolve(null)),
    Promise.resolve(null)
  );
}
mainAsync = mainSync;

or maybe more easy: 或更简单:

function mainAsync({a,b,c}){
  if(c) return C(c);
  if(b) return B(b);
  if(a) return A(a);
}

If you want all promises to be fullfilled before returning: 如果您希望在返回之前兑现所有承诺:

function mainAsync({a,b,c}){
 var promises=[];
  if(a) promises.push(A(a));
  if(b) promises.push(B(b));
  if(c) promises.push(C(c));
  return Promise.all(promises).then(val=>val.pop())
}

mainAsync({a:1,b:2,c:3});

If using ES7 transpilers (for async/await) is not an option, you can implement an async control flow using ES2015 generators . 如果不选择使用ES7编译器(用于异步/等待),则可以使用ES2015 生成器实现异步控制流。 Here's a naive example implementation: 这是一个简单的示例实现:

function *main() {
  let a = yield Promise.resolve(5);
  let b = yield Promise.resolve(a + 10);
  let c = yield Promise.resolve(b + 15);

  // place the rest of your code here
  console.log(c); // prints 30
}

function execAsync(generator, previousValue) {
  const nextValue = generator.next(previousValue);
  if (!nextValue.done) {
    let promise = nextValue.value;
    // FIXME: promise rejection is not handled
    promise.then(function (value) {
      execAsync(generator, value);
    });
  }
}

// ...    

// start the execution
execAsync(main());

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

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