【问题标题】:How to implement a callback? [duplicate]如何实现回调? [复制]
【发布时间】:2021-01-25 18:36:49
【问题描述】:

如何在getValue1函数中实现回调?

现在我变得不确定了?

我需要在 getAll 函数中获取“B”值

getAll 函数需要返回一个 promise,并且 getValue1 函数不能被更改。我该怎么做?

function getValue1(callback) {
  setTimeout(() => {
      callback("B");
  }, 10);
}

function getAll() {
   return Promise.all([getValue1(b => b)]);
}

getAll().then((arr) => console.log(arr));

【问题讨论】:

  • 这是奇怪的代码......为什么你使用 Promise.all 来处理不使用承诺的代码?如果您想在Promise.all 中轻松使用它,您需要从getValue1 返回一个Promise,而不是使用回调参数。
  • getAll 需要返回一个 promise,并且 getValue1 函数不能更改。我该怎么做?
  • function getValue1 无法更改,如何实现回调?

标签: javascript node.js ecmascript-6 promise


【解决方案1】:

创建一个函数来包装对 getValue1 的调用,使其解析为回调返回的值

const pvalue = () => new Promise(resolve => getValue1(resolve));

注意,这里是一样的

function pvalue() {
  return new Promise(function(resolve) {
    getValue1(value => resolve(value));
  });
}

所以, 价值 => 解决(价值)

是你对 getValue1 的回调 - 解决 pvalue 返回的 Promise

当然,

getValue1(value => resolve(value));

等价于

getValue1(resolve);

那么,您可以在Promise.all 中调用pvalue() 而不是getValue1(b=>b)

function getValue1(callback) {
    setTimeout(() => {
        callback("B");
    }, 10);
}
const pvalue = () => new Promise(resolve => getValue1(resolve));

function getAll() {
    return Promise.all([pvalue()]);
}

getAll().then((arr) => console.log(arr));

【讨论】:

    【解决方案2】:

    Continuation-passing style,即“回调”和 Promises 是处理异步代码的两种不同的机制。从历史上看,JavaScript 和 Node 使用函数回调,并且期望程序员遵循某些约定来编写他们的代码。因为很难遵循不强制的约定,所以编写回调代码是出了名的容易出错。 Promise 是一种较新的一流数据结构,它提供了更多专门为处理异步而设计的功能。


    如果你写 getValue1,

    整个 JavaScript 社区已广泛接受 Promises,并且为该语言添加了更多功能以利用它们的普遍性。你应该尽可能地编写基于 Promise 的代码。这意味着如果getValue1的作者,它不应该接受回调,而是返回一个promise -

    const delay = (ms, value) =>
      new Promise(r => setTimeout(r, ms, value))
    
    const getValue1 = _ =>
      delay(2000, "B")
    
    getValue1().then(console.log, console.error)
    
    console.log("please wait...")

    如果您愿意,您可以使用延续传递样式编写getValue1。 Node.js 使用约定,任何错误(如果存在)都将是回调的 first 参数。在 Node 中,您必须始终检查回调中是否存在错误,否则您可能会在程序中引入错误。为了遵循这个约定,你的代码看起来像 -

    const getValue1 = (callback) =>
      setTimeout(_ => callback(null, "B"), 2000)
    
    getValue1((err, res) => {
      if (err)
        console.error("error encountered:", err.message)
      else
        console.log("result:", res)
    })
    
    console.log("please wait...")

    如果继承 getValue1,

    当你继承回调风格的函数时,转换它是有益的,这样你就可以将它与新的基于 Promise 的代码一起使用。 Node.js 有一个内置函数util.promisify,可以做到这一点。出于演示目的,我在下面的示例中包含了我自己的promisify -

    const promisify = f => (...a) =>              // <- util.promisify
      new Promise
        ( (resolve, reject) =>
            f(...a, (e, v) => e ? reject(e) : resolve(v))
        )
    
    const getValue1 = (callback) =>               // <- old code
      setTimeout(_ => callback(null, "B"), 2000)
    
    const _getValue1 =
      promisify(getValue1)                        // <- promisify old code
      
    _getValue1().then(console.log, console.error) // <- back to sanity
    
    console.log("please wait...")

    接受承诺

    Promises 允许您利用 asyncawait 等新语言功能,显着改善代码阅读和编写体验 -

    const sleep = ms =>
      new Promise(r => setTimeout(r, ms))
    
    async function getValue1 ()
    { await sleep(1000)
      console.log("loading: 25%...")
      await sleep(1000)
      console.log("loading: 50%...")
      await sleep(1000)
      console.log("loading: 75%...")
      await sleep(1000)
      return "B"
    }
    
    async function main()
    { console.log("please wait...")
      const result = await getValue1()
      console.log("done:", result)
    }
    
    main().catch(console.error)
    please wait...
    loading: 25%...
    loading: 50%...
    loading: 75%...
    done: B
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多