【问题标题】:How do I serialize a Javascript array of functions returning Promises?如何序列化返回 Promises 的 Javascript 函数数组?
【发布时间】:2018-05-09 23:00:21
【问题描述】:

我的问题与this 非常相似,但我无法让它工作:(

问题:

  1. 我有一个 Javascript 程序需要在 IE11 和 Chrome 中运行。

  2. 它有一个我需要按顺序执行的函数列表。

  3. 每个函数都返回一个 Promise。 Promise.all(promisesArray) 可以“等待”直到所有功能完成后再继续。但它不保证每个函数都按顺序运行。这是必不可少的。

  4. 我尝试过使用Array.prototype.reduce(),但我无法弄清楚如何正确使用它。

  5. 因为需要在IE11中运行,所以不能使用“箭头函数”之类的ES6特性。

这是我的代码:

<script>
var fn = function(arg) {
  return new Promise (function (resolve, reject) {
    console.log("fn(" + arg + ")...");
    resolve("OK");
  });
}

var p = fn("A").then(function(r) {
  console.log("promise resolved: " + r + ".");
})

var chain = [];
chain.push(fn("3"));
chain.push(fn("1"));
chain.push(fn("2"));
console.log("Built chain:", chain);
Promise.all(chain);

chain.length = 0;
chain[2] = fn("30");
chain[1] = fn("20");
chain[0] = fn("10");
chain.reduce(function(promise, item) {
  return promise.then(function() {
    console.log("then:", item);
  }), Promise.resolve();
});
console.log("Done.");
</script>;

我需要按顺序执行的函数array[0], array[1], array[2]

【问题讨论】:

  • 如果函数应该按顺序运行,或者承诺应该按顺序解析,不要使用Promise.all
  • IE11 不支持 Promises。你在使用 Promise 库吗?为什么不使用转译器,这样您就可以同时使用 Promises 和 for...of 循环?
  • 就在5. "Because I need to run in IE11, I can't use ES6 features like "arrow functions"这一点上——箭头函数无关紧要,它们只是一种新语法,可以使用例如babljs轻松转换
  • @NathanPower - 编译器不会给你承诺 - 我知道这不是你的意思,但它有点像这样

标签: javascript es6-promise


【解决方案1】:

你真的很接近你的减速器!

reducer的初始值为Promise.resolve(),所以第一次调用函数时:

chain.reduce(function(promise, item) {
//                    ^^ promise is a resolved promise,
//                             ^^ item is chain[0]
  return promise.then(function() {
    console.log("then:", item);
    //           ^^ when the promise resolves (immediately) this is called
    //              BUT no value is returned.
  }), Promise.resolve();

});

将此与手动链接承诺进行比较。你会返回下一个等待的承诺:

Promise.resolve()
  .then(item => { console.log("then: ", item); return fn("10"); })
  .then(item => { console.log("then: ", item); return fn("20"); })
  .then(item => { console.log("then: ", item); return fn("30"); })

看看reducer怎么这么近?我们只想返回一个承诺:

var chain = [fn("10"), fn("20"), fn("30")];

chain.reduce(function(promise, item) {
  return promise.then(function() {
    console.log("then:", item);
    return item;
  }), Promise.resolve();
});

编辑
如果fn 调用开始工作,则这些分配中的每一个都将无序地开始调用:

chain.length = 0;
chain[2] = fn("30");
chain[1] = fn("20");
chain[0] = fn("10");

要按您想要的顺序运行每个fn,您必须将调用推迟到fn,直到上一个调用解决。我们在上面的手动示例中做到了这一点。根据您的数据的复杂程度,您可以减少 fn 的参数数组或将每个调用包装在一个不会运行的函数中:

[10,20,30]
  .reduce(function(promise, arg) {
    return promise.then(function() {
      return fn(arg);
    }), Promise.resolve();
  });

[function() { return fn(10); }, function() { return fn(20) }, function() { return fn(30) }]
  .reduce(function(promise, callFn) {
    return promise.then(function() {
      return fn(callFn);
    }), Promise.resolve();
  });

【讨论】:

  • 美丽:就是这样!非常感谢!额外信用奖励问题:您会在上面注意到,我明确设置了array[2]=fn(3)array[1]=fn(2)array[0]=fn(1)。我原以为它会执行“1、2、3”(索引顺序)。相反,它执行“3, 2, 1”(输入数组的顺序,与数组中元素的顺序OF。问:任何猜测“为什么”?问:任何解决方案?除了(重新)按所需顺序创建数组吗?
  • 因为调用fn(arg)是马上开始工作,所以实际上是按3、2、1的顺序调用的。如果你需要保证顺序,你不应该开始工作。这意味着要在很久以后调用fn。如果您从输入值开始:var values = [1,2,3];,您如何更改 reducer 以返回 Promise?
  • var values = [1,2,3]; values.reduce(function(promise, arg) { return promise.then(function() { return fn(arg); }), Promise.resolve(); })
  • 我不清楚。 fn(arg) 是一个工作单元。您的解决方案帮助我 a) 将任意“工作项”列表存储在一个数组中,然后 b) 依次执行每个项目。太好了-谢谢!但是“稍后再调用 fn”是什么意思?这到底是什么意思呢?我怎么能这样做?
  • 好吧,我们并没有让它按顺序执行工作项列表。我们将它们的结果链接起来,但是分配 array[2]=fn(3) 的行为会调用 fn 并开始工作。这就是顺序倒退的原因。要在函数执行时真正偷懒,您只需要在前一次调用完成后在 reducer 回调中调用 fn。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-30
  • 1970-01-01
  • 2021-06-07
  • 1970-01-01
  • 1970-01-01
  • 2016-01-13
相关资源
最近更新 更多