我只想运行一个异步函数,让它等待它有一个返回值,将该返回值传递给另一个异步功能,然后清洗并重复几次。我看到了一些例子,但我正在努力使它们在测试代码中发挥作用。请原谅所有的棒球背景,但我不得不为自己造成的鼻出血找点乐子。
如果不在附加的代码中传递返回值,我甚至无法使其工作,现在感觉很愚蠢。。。
whosOnFirst(1)
.then(whatsOnSecond(2))
.then(iDunnosOnthird(3))
我想看看执行whosOnFirst(1)的语法,将返回值传递给whatsOnSecond(),并将其返回值传递到iDunnosOnthird()。创建代码段底部引用的所需输出(减去空格)。
我真的很感激你的帮助!
// Arbitrary timer with input/output parameters for async understanding;
function waitSec(callerName, pause) { //
console.log(`${callerName} called, waiting ${pause} second(s)...`)
setTimeout(function () {
console.log(`${callerName} sent ${pause + 1} in a return, and done!`)
return pause + 1; // delayed return value / adds 1 to input param
}, pause * 1000);
}
// Who's On First - run this first with an input param = 1
async function whosOnFirst(i) {
waitSec("who's on first", 1).then(result => {
return result;
})
}
// What's on Second - run after completion of whosOnFirst() using return for param
async function whatsOnSecond(i) {
waitSec("what's on second", i).then(result => {
return result;
})
}
// iDunno's on third - run after completion of whatsOnSecond(i) using return for param
async function iDunnosOnthird(i) {
waitSec("iDunno's on third", i).then(result => {
return result;
})
}
whosOnFirst(1)
.then(whatsOnSecond(2))
.then(iDunnosOnthird(3))
// CURRENT OUTPUT:
// who's on first called, waiting 1 second(s)...
// what's on second called, waiting 2 second(s)...
// iDunno's on third called, waiting 3 second(s)...
// who's on first sent 2 in a return, and done!
// what's on second sent 3 in a return, and done!
// iDunno's on third sent 4 in a return, and done!
// DESIRED OUTPUT:
// who's on first called, waiting 1 second(s)...
// who's on first sent 2 in a return, and done!
// what's on second called, waiting 2 second(s)...
// what's on second sent 3 in a return, and done!
// iDunno's on third called, waiting 3 second(s)...
// iDunno's on third sent 4 in a return, and done!
工作解决方案
您的问题是waitSec
与代码的其余部分处于不同的上下文中。您需要将其提升到Promise上下文中。
然后,您就可以一直"promised"代码,并且可以将promises链接起来。它在这里工作(下面会有进一步的解释):
// Arbitrary timer with input/output parameters for async understanding;
function waitSec(callerName, pause) { //
return new Promise(resolve => {
console.log(`${callerName} called, waiting ${pause} second(s)...`)
setTimeout(function () {
console.log(`${callerName} sent ${pause + 1} in a return, and done!`)
resolve(pause + 1); // delayed return value / adds 1 to input param
}, pause * 1000);
})
}
// Who's On First - run this first with an input param = 1
function whosOnFirst(i) {
return waitSec("who's on first", 1)
}
// What's on Second - run after completion of whosOnFirst() using return for param
function whatsOnSecond(i) {
return waitSec("what's on second", i)
}
// iDunno's on third - run after completion of whatsOnSecond(i) using return for param
function iDunnosOnthird(i) {
return waitSec("iDunno's on third", i)
}
whosOnFirst(1)
.then(whatsOnSecond)
.then(iDunnosOnthird)
.then(console.log)
进一步解释
waitSec
的原始实现总是将undefined
返回给调用者:
// Arbitrary timer with input/output parameters for async understanding;
function waitSec(callerName, pause) { //
console.log(`${callerName} called, waiting ${pause} second(s)...`)
setTimeout(function () {
console.log(`${callerName} sent ${pause + 1} in a return, and done!`)
return pause + 1; // delayed return value / adds 1 to input param
}, pause * 1000);
// return undefined happens here
}
setTimeout
内部的返回不会返回到您的调用代码,因为您的代码从不调用此函数。它由JS定时器代码异步调用。
使用回调从异步代码返回值
将结果传递给调用者的方法是将回调作为外部函数的参数,然后在异步函数中调用该回调,如下所示:
function waitSec({callerName, pause, callback}) {
console.log(`${callerName} called, waiting ${pause} second(s)...`)
setTimeout(function () {
console.log(`${callerName} sent ${pause + 1} in a return, and done!`)
callback(pause + 1); // delayed return value / adds 1 to input param
}, pause * 1000);
}
在这种情况下,您有JS的经典回调模式。
使用承诺,以及您可能更喜欢它们的原因
或者,您返回一个Promise,并解析它以返回值——正如我在解决方案中演示的那样。有关这方面的更多信息,请搜索"我如何承诺回调"。
这样做(使用Promise)的好处是Promise是可组合的,如解决方案中所示。
Promise也可以使用await
,因此可以使用带有Promise返回函数的async
/await
。
您不需要将Promise返回函数标记为async
。
如果将函数标记为async
,它将返回Promise,如下所示:
// A function marked async returns a Promise
async function simple() {
return 3
}
// Proof that it is a Promise
simple().then(console.log)
// The equivalent code explicitly returning a Promise - this is what `async` does
function simpleP(n = 0) {
return new Promise(resolve => resolve(n+1))
}
// Proof that it behaves the same
simpleP().then(console.log)
// Promise composition
simple()
.then(simpleP)
.then(console.log)
// Same functionality, using async/await
async function main() {
const num = await simple()
const res = await simpleP(num)
console.log(`${num} + 1 = ${res}`)
}
main()
标记同步返回函数async
使它们可以与实际需要Promise来返回值的异步代码组合。您可以使用它将函数提升到相同的异步上下文中并组合它们。
// Synchronous function that is Promisified and composable
async function simple() {
return 3
}
要从接受回调并通过回调提供返回的异步函数中实际获取值,必须从函数中构造并返回Promise,然后在提供要通信的值的回调中调用Promiseresolve
。
function getDBRecordP(id) {
return new Promise((resolve, reject) =>
dbLib.get(id,
(err, result) => err ?
reject(err) :
resolve(result)))
}
在这种情况下,您必须明确地连接Promise机制。这几乎是您需要创建并返回Promise的唯一时间。
它所做的是为您包装一个回调接口。
function getDBRecordP(id) {
return new Promise((resolve, reject) =>
dbLib.get(id,
(err, result) => err ?
reject(err) :
resolve(result)))
}
请注意,在回调示例中,您必须将调用方的callback
参数作为参数,然后在提供该值的回调中使用返回值来调用该参数。
使用Promise机制,您确实接受了一个回调参数,但它不是由调用者提供的,而是由您构造的Promise提供的。然后您将Promise返回给呼叫者。
上面的getDBRecordP
函数是"如何将接受回调的函数转换为返回Promise的函数?"的精髓。
然后,调用者将回调传递给Promise.then()
方法。
因此,您有一台机器,它将回调传递约定封装到可组合的正式API中,而回调则不是。
Promise机器的另一个方面是.catch()
方法。
对于回调,惯例一直是回调签名为(err, result)
,而Promise机器允许您提供两个回调,一个用于err
,一个为result
。
请使用对async
函数来说很漂亮的await
关键字。你的waitSec
函数应该返回一个promise,当你解析promise时,你的值出现在.then((res)=> console.log(res))
中,使用它进行如下链接:
// Arbitrary timer with input/output parameters for async understanding;
function waitSec(callerName, pause) { //
return new Promise((resolve, reject) => {
console.log(`${callerName} called, waiting ${pause} second(s)...`)
setTimeout(function() {
console.log(`${callerName} sent ${pause + 1} in a return, and done!`)
resolve(pause + 1); // delayed return value / adds 1 to input param
}, pause * 1000);
})
}
// Who's On First - run this first with an input param = 1
async function whosOnFirst(i) {
const resp = await waitSec("who's on first", 1);
return resp;
}
// What's on Second - run after completion of whosOnFirst() using return for param
async function whatsOnSecond(i) {
const resp = await waitSec("what's on second", i);
return resp;
}
// iDunno's on third - run after completion of whatsOnSecond(i) using return for param
async function iDunnosOnthird(i) {
const resp = await waitSec("iDunno's on third", i);
return resp;
}
whosOnFirst(1).then((firstResp) => {
whatsOnSecond(firstResp).then((secResp) => {
iDunnosOnthird(secResp).then((thirdResp) => {
console.log(thirdResp);
})
})
})
您也可以将链中的值与async/await
:一起使用,如下所示
// Arbitrary timer with input/output parameters for async understanding;
function waitSec(callerName, pause) { //
return new Promise((resolve, reject) => {
console.log(`${callerName} called, waiting ${pause} second(s)...`)
setTimeout(function() {
console.log(`${callerName} sent ${pause + 1} in a return, and done!`)
resolve(pause + 1); // delayed return value / adds 1 to input param
}, pause * 1000);
})
}
// Who's On First - run this first with an input param = 1
async function whosOnFirst(i) {
const resp = await waitSec("who's on first", 1);
return resp;
}
// What's on Second - run after completion of whosOnFirst() using return for param
async function whatsOnSecond(i) {
const resp = await waitSec("what's on second", i);
return resp;
}
// iDunno's on third - run after completion of whatsOnSecond(i) using return for param
async function iDunnosOnthird(i) {
const resp = await waitSec("iDunno's on third", i);
return resp;
}
let test = async() => {
var res1 = await whosOnFirst(1);
var res2 = await whatsOnSecond(res1);
var res3 = await iDunnosOnthird(res2);
console.log(res3);
}
test();
您需要等待每个结果,如下所示:
async function main() {
const result1 = await whosOnFirst(1);
// whosOnSecond will not get called except after the whosOnFirst is done.
const result2 = await whosOnSecond(result1);
}
以下是它的工作原理:
function delay(milliseconds){
return new Promise((resolve)=>{
setTimeout(()=>{
resolve();
}, milliseconds);
});
}
async function test(){
console.log('no delay, yet');
await delay(1000);
console.log('After 1 second');
await delay(1000);
console.log('2 seconds have passed');
await delay(3000);
console.log('Oh look, 5 seconds have passed!');
}
test();
async
函数await
,直到Promise
是resolve
d,然后转到Promise
之后的下一个代码块,可能是await
ing。。。再一次。我承认我觉得奇怪的是,async
函数真的同步运行await
,但async
函数本身是异步的。。。意味着紧接在执行的CCD_ 33之后执行的另一个函数可能在CCD_。
关于你的例子:
class Counter{
constructor(increment = 1, initially = 0){
this.increment = increment; this.count = initially;
}
inc(){
return this.count += this.increment;
}
dec(){
return this.count -= this.increment;
}
}
function delay(milliseconds){
return new Promise((resolve)=>{
setTimeout(()=>{
resolve();
}, milliseconds);
});
}
const sec = new Counter;
function logCaller(callerName){
console.log(`${callerName} called, after ${sec.inc()} second(s)...`);
}
async function what(){
await delay(1000);
logCaller("who's on first");
await delay(1000);
logCaller("what's on second");
await delay(1000);
logCaller("iDunno's on third");
}
what();