我想编写两个函数,将Promises返回到一个返回Promise的函数中。
我真的想为异步系统调用执行此操作,但为了简化操作,现在我正在玩围绕setTimeout的Promise。大多数系统调用可以按任何顺序发送和返回,但在少数情况下,需要来自一个系统调用的数据来创建第二个系统调用。
在随附的示例中,我想发送间隔为5秒,然后是3秒,然后是10秒的警报。当我运行代码时,事情的顺序错误。
我注释掉了代码,我可以运行两个以“.then”链接的调用。注释掉的代码可以按需运行。但我还没有弄清楚如何将它放入一个返回一个承诺的函数中,并且仍然有效。
我只对使用纯JavaScript执行此操作感兴趣。在我理解了如何做到这一点之后,我会看一下使用库做同样的答案。
// 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);
});
答案 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”。
评估未定义。没有承诺要解决。
// 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)
);