NodeJS 如何理解这种等待/等待练习?

ha5z0ras  于 11个月前  发布在  Node.js
关注(0)|答案(4)|浏览(91)

我正在做async/await上的一些练习,我在这一个上完全空白:
​​opA函数必须在opB之前调用,opB​必须在​opC之前调用。调用函数的方式是​C,然后​B,然后​A被打印出来。

const print = (err, contents) => {
  if (err) console.error(err)
  else console.log(contents )
}

const opA = (cb) => {
  setTimeout(() => {
    cb(null, 'A')
  }, 500)
}

const opB = (cb) => {
  setTimeout(() => {
    cb(null, 'B')
  }, 250)
}

const opC = (cb) => {
  setTimeout(() => {
    cb(null, 'C')
  }, 125)
}

字符串
我的猜测是有一个错字的问题,所以我应该只是有功能打印出A B C,而不是C B A

我的尝试是:

(async function () {
  await print(opA());
  await print(opB());
  await print(opC());
}());


但我得到

cb(null, 'C')
    ^

TypeError: cb is not a function

问题

我真的不知道如何解决这个问题,也不明白print函数的用法。
任何帮助如何让我去将不胜感激=)

nhaq1z21

nhaq1z211#

你说这是一个回调/await练习,但你展示的代码完全是回调/await的对立面--它使用了回调范式。
要让你的代码打印C B A,你需要按照这样的顺序将回调传递给opX函数,让它们打印结果:

const print = (err, contents) => {
  if (err) console.error(err)
  else console.log(contents )
}

const opA = (cb) => {
  setTimeout(() => {
    cb(null, 'A')
  }, 500)
}

const opB = (cb) => {
  setTimeout(() => {
    cb(null, 'B')
  }, 250)
}

const opC = (cb) => {
  setTimeout(() => {
    cb(null, 'C')
  }, 125)
}

opA(print);
opB(print);
opC(print);

字符串

ao218c7q

ao218c7q2#

存储在optAopBopC中的函数接受在超时时调用的回调函数cb,第一个参数设置为null,第二个参数设置为ABC
print包含一个函数,它接受一个错误(err)作为第一个参数,并接受要打印的内容作为第二个参数(contents)。
因此,您可以通过以下方式将opt函数与print合并组合:optA(print)
按照目前的问题形式,它只是:

opA(print)
opB(print)
opC(print)

字符串

const print = (err, contents) => {
  if (err) console.error(err)
  else console.log(contents )
}

const opA = (cb) => {
  setTimeout(() => {
    cb(null, 'A')
  }, 500)
}

const opB = (cb) => {
  setTimeout(() => {
    cb(null, 'B')
  }, 250)
}

const opC = (cb) => {
  setTimeout(() => {
    cb(null, 'C')
  }, 125)
}

opA(print)
opB(print)
opC(print)


要获得结果:CBA(由于setTimeouts使用的延迟)。
但问题中可能缺少一些东西。

ctehm74n

ctehm74n3#

你调用这些函数的顺序几乎与所需的结果无关。定时器被设置为按照特定的顺序运行,首先是C,然后是B,然后是A
你可以直接叫他们:

opA(print);
opB(print);
opC(print);

字符串
或者甚至:

opB(print);
opA(print);
opC(print);


或者甚至:

opC(print);
opB(print);
opA(print);


但是,有一些方法可以切换顺序,这将给予错误的结果。例如:

opA((err, a) => (
   print(err, a),
   opB((err,b) => (
       print(err, b),
       opC(print)
   ))
))


它将在opA设置的计时器运行后调用opB,并在opB计时器运行后调用opC
我相信这个练习的目的可能是让你可以观察到,你调用函数的顺序并不总是反映你直觉上期望的顺序。

0aydgbwb

0aydgbwb4#

这个问题很像我花了一些时间做的一个实验练习。下面是三个解决方案。

  • 请注意,在实验中,promisfy模块包含在提示符中;然而,回调解决方案(第一个解决方案)根本不需要promsify。*

首先,代码提示:

'use strict'
const { promisify } = require('util')

const print = (err, contents) => {
  if (err) console.error(err)
  else console.log(contents)
}

const opA = (cb) => {
  setTimeout(() => {
    cb(null, 'A')
  }, 500)
}

const opB = (cb) => {
  setTimeout(() => {
    cb(null, 'B')
  }, 250)
}

const opC = (cb) => {
  setTimeout(() => {
    cb(null, 'C')
  }, 125)
}

字符串
指令说“A,然后B,然后C [必须]打印出来”,特别是按照这个顺序。当然,简单地通过传递print回调来调用每个函数,会以完全错误的顺序打印它们(由于巧妙制作的超时)。

解决方案

解决方案一,回调

第一个解决方案的重点是提供一个回调函数,而不是print()回调函数。调用opA(print)很容易,如果你想让它们并行运行,那么它就可以工作。
要以给定的顺序串行同步运行这些函数,每个函数都必须在下一个函数之前完成。要实现这一点,可以创建一个稍微复杂一点的回调函数,如下所示:

opA((err, out) => {
  // opA() completed...pass opA output to print()
  print(err, out)

  // now call opB() from within the opA() callback
  opB((err, out) => {

    // opB() completed...pass the opB output to print()
    print(err, out)

    // etc...
    opC((err, out) => {
      print(err, out)
    })
  })
})

解决方案二,使用Then/Catch的Promises

第二种和第三种解决方案使用promisfy模块。
解决方案2使用thencatch。为了简化解决方案,我们可以省略catch()(但是,不建议在生产应用程序中省略catch)。
在我看来,保证函数使用then/catch会使简单的回调解决方案(解决方案1)变得过于复杂。因此,解决方案1和解决方案2都是它们自己的私有回调地狱。

const a = promisify(opA);
const b = promisify(opB);
const c = promisify(opC);

a()
  .then((out)=> {

    // just like the callback solution
    // we wait in this `then` to call `print`
    print(null, out)

    // and just like in the callback solution
    // now we nest another layer of callback hell
    b()
      .then((out)=> {
        print(null, out)

        // etc...
        c()
          .then((out)=> {
             print(null, out)
          })
      })
  })

解决方案三,Async/Await的Promises

解决方案3是最现代和灵活的,它实现了asyncawait

  • 注意事项:opA()、opB()和opC()返回的两个变量通过以下语句被解构为变量errout[err, out] = await a()。*
const a = promisify(opA);
const b = promisify(opB);
const c = promisify(opC);

const main = async () => {

  let [err, out] = await a();
  print(err, out);

  [err, out] = await b();
  print(err, out);

  [err, out] = await c();
  print(err, out);
}
main();

相关问题