return 承诺的嵌套函数数组

Nest array of functions that return promises

这里我有 4 个 return 承诺的功能。如果你 运行 hello 并将每个传递给下一个 .then 你会得到一个长字符串。

var hello = function(str){
  return Promise.resolve(str+ "hello")
}
var world = function(str){
  return Promise.resolve(str+ "world")
}
var foo = function(str){
  return Promise.resolve(str+ "foo")
}
var bar = function(str){
  return Promise.resolve(str+ "bar")
}

// hello("alpha").then(world).then(foo).then(bar).then(console.log)
// => alphahelloworldfoobar

我希望能够将函数的平面数组传递给一个函数并得到 return 一个将它们全部嵌套的函数。

var arr = wrapThen([
  hello,
  world,
  foo,
  bar
])

arr("alpha").then(console.log)

这可能吗? bluebird 提供这个吗?

这是我一起破解的:

function wrapThen(arr){
  var headPromise = arr.shift()
  return function(){
    var args = _.values(arguments)
    var init = headPromise(args)
    var values = []
    return Promise.each(arr, function(item){
      init = init.then(item)
      return init.then(function(value){
        values.push(value)
        return value
      })
    }).then(function(){
      return _.last(values)
    })
  }
}

不确定您是否希望所有函数都获得相同的参数 alpha 或仍然按顺序传递,所以我写了两者,只需使用 .reduce.map 就可以实现这两种方式。

var hello = function(str){
  return Promise.resolve(str+ "hello");
};
var world = function(str){
  return Promise.resolve(str+ "world");
};
var foo = function(str){
  return Promise.resolve(str+ "foo");
};
var bar = function(str){
  return Promise.resolve(str+ "bar");
};
 
// Wrap all functions in list, all give them the same value.
var wrapToArray = function(list) {
  
  return function(result) {
    var allP = list.map(function(item) {
      return item(result);
    });
    return Promise.all(allP);
  };
  
};

// Wraps all, and resolve them by array's sequence.
var wrapToSequence = function(list) {
  
   return  function(result) {
    // Create a promise that resolved with result first.
    var promise = Promise.resolve(result);
    // Use reduce to chain the functions.
    promise = list.reduce(function(prev, item) {
      return prev.then(item);
    }, promise);
    return promise;
  };

};

var arr = wrapToArray([hello, world, foo, bar]);
var arr2 = wrapToSequence([hello, world, foo, bar]);

arr("alpha").then(console.log.bind(console));
arr2("alpha").then(console.log.bind(console));
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/2.9.33/bluebird.min.js"></script>

Bluebird 还提供 .reduce, .map to create it easier, to avoid the answer become longer, demo is on jsfiddle.

var wrapToSequence = function(list) {
   return  function(result) {
    return  Promise.reduce(list, function(result, fn) {
      return fn(result);
    }, result);
  };
};

var wrapToArray = function(list) {
  return function(result) {
    return Promise.map(list, function(fn) {
      return fn(result);
    });
  };
};

当然,使用 reduce 的蓝鸟很容易做到这一点,这基本上就是 reduce 所做的(总结果):

let result = Promise.reduce([hello, world, foo, bar], function(result, action){
    return action(result);
}, "alpha");

在 ES2015 符号中,这变得更加简洁:

let {reduce} = Promise;
let result = reduce(arr, (result, action) => action(result), "alpha");

var hello = function(str){
  return Promise.resolve(str+ "hello");
};
var world = function(str){
  return Promise.resolve(str+ "world");
};
var foo = function(str){
  return Promise.resolve(str+ "foo");
};
var bar = function(str){
  return Promise.resolve(str+ "bar");
};


Promise.reduce([hello, world, foo, bar], function(result, action){
    return action(result);
}, "alpha").then(function(endResult){ 
    console.log(endResult);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/2.9.33/bluebird.min.js"></script>

这是一个如何使用 Ramda 执行此操作的示例。

var R = require("ramda")

var hello = function(str){
  return Promise.resolve(str+ "hello")
}
var world = function(str){
  return Promise.resolve(str+ "world")
}
var foo = function(str){
  return Promise.resolve(str+ "foo")
}
var bar = function(str){
  return Promise.resolve(str+ "bar")
}

var result = R.pipeP(hello, world, foo, bar)

result("alpha").then(console.log) // logs -> "alphahelloworldfoobar"

result("alpha") // promise -> "alphahelloworldfoobar"