撰写返回Promises的函数

时间:2018-04-09 22:19:50

标签: javascript es6-promise

我想编写两个函数,将Promises返回到一个返回Promise的函数中。

我真的想为异步系统调用执行此操作,但为了简化操作,现在我正在玩围绕setTimeout的Promise。大多数系统调用可以按任何顺序发送和返回,但在少数情况下,需要来自一个系统调用的数据来创建第二个系统调用。

在随附的示例中,我想发送间隔为5秒,然后是3秒,然后是10秒的警报。当我运行代码时,事情的顺序错误。

我注释掉了代码,我可以运行两个以“.then”链接的调用。注释掉的代码可以按需运行。但我还没有弄清楚如何将它放入一个返回一个承诺的函数中,并且仍然有效。

我只对使用纯JavaScript执行此操作感兴趣。在我理解了如何做到这一点之后,我会看一下使用库做同样的答案。

jsfiddle

// Returns a Promise.
// I purposely chose not to use the callback function inside setTimeout in order to demonstrate
// how to combine functions which return Promises, and normal functions which don't.
function sleep(delay, callbackFunction) {
  return new Promise(function(resolve) {
    setTimeout(resolve.bind(null, callbackFunction), delay)
  });
}

// Normal function, does not return a promise.
const myPrint = (message, value) => {
  alert(message + " " + value);
};

// A function combining a promise and then a normal function.
// Returns a Promise.
const sleepPrint = (delay) => {
  return sleep(delay)
    .then(() => {
      myPrint("sleepPrint()", delay);
    });
};

// A function combining two functions which return promises.
// Returns a Promise.
const sleepPrintSleepPrint = (delay1, delay2) => {
  return sleepPrint(delay1)
  .then(sleepPrint(delay2));
};

alert("Begin");
/*
// Run a Pomise function, then a normal function.
const delay = 4000;
sleep(delay)
.then(() => {
  myPrint("init", delay);
});
*/

const firstDelay = 5000;
const secondDelay = 3000;

/*
// Call sleepPrint() which runs a Promise function then a normal function.
// After all that finishes, call another Promise function, than another normal function.
// This code works as desired, but the code at the bottom doesn't!
sleepPrint(firstDelay)
.then(() => {
  return sleep(secondDelay)
})
.then(() => {
  myPrint("After sleepPrint() and sleep()", secondDelay);
});
*/

// Comine two calls to sleepPrint() into a new functiion which returns a Promise, sleepPrintsleepPrint().
// After all that finishes, call another Promise function, than another normal function.
// I want this to have 5 second delay and then a 3 second delay, but they are not running in that order.
const thirdDelay = 10000;
sleepPrintSleepPrint(firstDelay, secondDelay)
.then(() => {
  return sleep(thirdDelay)
})
.then(() => {
  myPrint("After sleepPrintSleepPrint()", thirdDelay);
});

2 个答案:

答案 0 :(得分:2)

记住函数的工作原理(使用任何编程语言)。这样:

const sleepPrintSleepPrint = (delay1, delay2) => {
  return sleepPrint(delay1)
  .then(sleepPrint(delay2));
};

与此相同:

const sleepPrintSleepPrint = (delay1, delay2) => {
  var x = sleepPrint(delay2);
  return sleepPrint(delay1)
  .then(x);
};

您正在做的是同时调用这两个函数。我认为你想要的是调用第二个函数然后解析。所以你需要这样做:

const sleepPrintSleepPrint = (delay1, delay2) => {
  return sleepPrint(delay1)
  .then(function(){return sleepPrint(delay2)});
};

或者如果您更喜欢箭头函数语法:

const sleepPrintSleepPrint = (delay1, delay2) => {
  return sleepPrint(delay1)
  .then(() => sleepPrint(delay2));
};

答案 1 :(得分:0)

@slebetman提供了正确的代码,他在高级别上正确解释了问题和修复。这是我对他的答案的更详细的理解。这应该是对他的答案的评论,但它太大了。

JavaScript解释器通过代码进行两次传递,其中包含链接的“.then”s。

第一次传递立即发生,没有任何等待,并评估“.then”的参数。

第二遍传递第一遍中返回的结果值,然后计算结果值。在第二次传递中,解释器在评估结果值之前一直等到先前的promise被解决。

通常,“.then”的参数是一个返回第二个函数(或对函数的引用)的函数。在第一遍中,没有什么非常有趣的事情发生,评估一个函数,结果值是第二个函数。然后在第二遍中,在解决了上一个承诺之后,将评估第二个函数。

以下是此行为的示例。

首次通过

  • 启动sleepPrint(firstDelay)。让它在后台运行。

  • 立即转到下一个“.then”。

  • 打印第一条消息。保存结果值,未定义(可能?)

  • 立即转到下一个“.then”。

  • 评估返回sleepPrint(secondDelay)的匿名函数。保存结果值,函数sleepPrint(secondDelay)。

  • 立即转到下一个“.then”。

  • 打印第二条消息。保存结果值,未定义(可能?)

第二次通过

  • 等到sleepPrint(firstDelay)打印第三条消息,然后解析,然后转到下一个“.then”。

  • 评估未定义。没有承诺要解决,所以转到下一个“.then”。

  • 启动sleepPrint(secondDelay),打印第四条消息。等待承诺得到解决,然后转到下一个“.then”。

  • 评估未定义。没有承诺要解决。

jsFiddle

// Returns a Promise.
// I purposely chose not to use the callback function inside setTimeout in order to demonstrate
// how to combine functions which return Promises, and normal functions which don't.
function sleep(delay, callbackFunction) {
  return new Promise(function(resolve) {
    setTimeout(resolve.bind(null, callbackFunction), delay)
  });
}

// Normal function, does not return a promise.
const myPrint = (message, value) => {
  alert(message + " " + value);
};

// A function combining a promise and then a normal function.
// Returns a Promise.
const sleepPrint = (delay) => {
  return sleep(delay)
    .then(() => {
      myPrint("sleepPrint()", delay);
    });
};

alert("Begin");

const firstDelay = 5000;
const secondDelay = 3000;

// This message is printed third.
sleepPrint(firstDelay)
.then(
  myPrint("This message is printed first", 0)
)
.then(
  // This message is printed fourth.
  () => {sleepPrint(secondDelay)}
)
.then(
  myPrint("This message is printed second", 0)
);