简体   繁体   English

从对象创建异步瀑布

[英]Create asynchronous waterfall from objects

Say I have an array of objects which have asynchronous methods: 说我有一个具有异步方法的对象数组:

[
  {
    partOne: function(input) {
      // Do something async
    },
    partTwo: function(result) {
      // Do something w/ result of partOne
    }
  },
  {
    partOne: function(resultOfPrevious) {
      // Do something async
    },
    partTwo: function(result) {
      // Do something w/ result of partOne
    }
  },
  {
    partOne: function(resultOfPrevious) {
      // Do something async
    },
    partTwo: function(result) {
      // Do something w/ result of partOne
    }
  }
]

I want to execute partOne of the first object with my input, pass the result (async) to the partTwo callback, then pass the result of partTwo as input to partOne of the next object and so on. 我想用输入执行第一个对象的partOne,将结果(异步)传递给partTwo回调,然后将partTwo的结果作为输入传递给下一个对象的partOne,依此类推。 The array may be of one or more objects. 该阵列可以是一个或多个对象。 I'm wondering what the best pattern to execute this kind of code is? 我想知道执行这种代码的最佳模式是什么?

It is somewhat similar to the waterfall method of async.js: https://caolan.github.io/async/docs.html#waterfall , but I wonder how I can do this without a library and possibly with cleaner code? 它有点类似于async.js的瀑布方法: https ://caolan.github.io/async/docs.html#waterfall,但我想知道如何在没有库且可能没有更干净的代码的情况下做到这一点?

Not sure if async/await might help here? 不确定async / await是否对您有所帮助?

Another option without collecting every callback to an array, using async/await : 另一种选择是使用async/await而不将每个回调收集到数组中:

async function processWaterfallObject (data, input) {
  let result = input

  for (let entry of data) {
     result = await entry.partOne(result)
     result = await entry.partTwo(result)
  }

  return result
}

This assumes that functions in your data array are either async or return a Promise . 假定data数组中的函数要么async要么返回Promise


async/await is currently supported by every major browser and is available in node since 7.6.0 . 每个主要浏览器当前都支持async/await ,并且从7.6.0开始在node 7.6.0

Here is a simple function to invoke each asynchronous function in a stack 这是调用堆栈中每个异步函数的简单函数

function drain(stack, initialArg) {
  stack.reduce(function (sectArg, section) {
    return Object.keys(section).reduce(async function (arg, key) { 
      return await section[key].call(null,arg)
    }, sectArg) 
  }, initialArg)
}

To use it ensure that each function in you stack returns a value 要使用它,请确保堆栈中的每个函数都返回一个值

var stack = [
  {
    partOne: function(input) {
      // Do something async
      console.log('section one  partOne', input)
      return 'section one partOne output'
    },
    partTwo: function(result) {
      // Do something w/ result of partOne
      console.log('section one  partTwo', result)
      return 'section one partTwo output'
    }
  },
  {
    partOne: function(resultOfPrevious) {
      // Do something async
      console.log('section two  partOne', resultOfPrevious)
      return 'section two partOne output'
    },
    partTwo: function(result) {
      // Do something w/ result of partOne
      console.log('section two  partTwo', result)
      return 'section two  partTwo output'
    }
  },
  {
    partOne: function(resultOfPrevious) {
      // Do something async
      console.log('section three  partOne', resultOfPrevious)
      return 'section three partOne output'
    },
    partTwo: function(result) {
      // Do something w/ result of partOne
      console.log('section three  partTwo', result)
      return 'section three partTwo output'
    }
  }
]

So that you can invoke the stack like 这样您就可以像

drain(stack, 'initialArg')

See this jsfiddle: https://jsfiddle.net/kqj0rror/ 看到这个jsfiddle: https ://jsfiddle.net/kqj0rror/

Assuming your array of objects given in the original question is under a variable called waterfall 假设原始问题中给定的对象数组在一个名为Waterfall的变量下

let collector = [];
for (waterfallObj of waterfall) {
  let tempArr = Object.values(waterfallObj);//get the functions out of the object
  for (waterfallFunc of tempArr) {
    collector.push(waterfallFunc);
  }
}
//now you have your functions in order in collector
function recursiveCallback(i) {
  if (i>collector.length-1) {
    return;//if there are no more to call then return
  }

  collector[i]().then(function(){
    recursiveCallback(i+1);
  });
}

If you want the next function to do something with the previous functions value then simply change the then to then(function(passedValue and then use that passedValue in the recursiveCallback call within it 如果您希望下一个函数对前一个函数的值做某事,则只需将then更改为then(function(passedValue,然后在其中的recursiveCallback调用中使用该passValue

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

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