【问题标题】:Execute Promise tree consecutively from parent to child从父级到子级连续执行 Promise 树
【发布时间】:2019-01-08 00:11:36
【问题描述】:

我想使用嵌套的Promise's 创建一个树形结构。

当 Promise 在树结构中解析时,它将从内到外解析(子节点然后父节点)。我需要让从父到子的兄弟承诺的执行可以并行运行。

我想出了一种方法来延迟执行,方法是解决一个闭包,该闭包将延迟已解决的承诺的操作,并从上到下递归调用每个函数。这是一个相当优雅的解决方案,但是,我可以使用任何其他约定或功能对象来执行该操作。我真的不想解决树中每个节点的闭包问题,因为这会增加教人们使用它的复杂性。

我宁愿不使用 async/await,而是坚持使用 Promise 或其他函数式 JS 对象。

第一个示例将显示嵌套 Promise 的解析顺序。

let order = 0
const promiseTree = (name, children) => 
  Promise.all([
    new Promise(res => res(`${name} order:${order++}`)),
    children && Promise.all(children)
  ])

promiseTree('root', [
  promiseTree('child', [
    promiseTree('grandchild', [
      promiseTree('great grandchild sibling 1'),
      promiseTree('great grandchild sibling 2'),
    ])
  ])
])
.then(console.log)
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js?concise=true"></script>

如果您解决了一个闭包,则在所有承诺完成后递归调用回调,可以更正订单。

let order = 0
const promiseTree = (name, children) => 
  Promise.all([
    // --------------------- resolve a closure with the resolved value contained
    new Promise(res => res(() => `${name} order:${order++}`)),
    children && Promise.all(children)
  ])

// flatMap over the tree, if it's a function call it and return the result
const recursivelyCall = x => 
  Array.isArray(x)
    ? x.map(recursivelyCall)
    : typeof(x) === 'function' ? x() : x

promiseTree('root', [
  promiseTree('child', [
    promiseTree('grandchild', [
      promiseTree('great grandchild sibling 1'),
      promiseTree('great grandchild sibling 2'),
    ])
  ])
])
// traverse the returned values and call the functions in declared order
.then(recursivelyCall)
.then(console.log)
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js?concise=true"></script>

干杯

【问题讨论】:

  • 在您的第一个示例中,您没有显示执行顺序,而是显示已解决的顺序。 IOW:做一个 console.log 并解析你会更好地看到它的值。
  • @Keith 对不起,我说错了。我只关心承诺的解决顺序。它们用于异步节点树中,例如父节点可以从服务器下载html模板,子节点可以向html模板添加功能,因此父节点必须在子节点之前执行。第一个例子表明,孩子首先被执行。
  • 我对这个问题有点坚持,因为“返回闭包”和“解决闭包”并不正确。闭包不是可以返回或解决的东西。
  • @Roamer-1888 感谢您指出差异。我已将其更正以解决,因为您无法从承诺中返回值。闭包只是表达功能的一种方式。它可以从 Promise 中解析,然后从 then 函数中调用。例如。 Promise.resolve(() => 'resolved value').then(fn => console.log(fn()))

标签: javascript promise functional-programming tree


【解决方案1】:

第一个 sn-p 代码中模式的问题是最内层的嵌套函数(参数)首先执行;在https://astexplorer.net/#/gist/777805a289e129cd29706b54268cfcfc/5a2def5def7d8ee91c052d9733bc7a37c63a6f67https://github.com/tc39/ecma262/issues/1397 处查看并突出显示行15

我宁愿不使用 async/await 并坚持使用 Promise's 或其他函数式 JS 对象。

尚不清楚为什么该选项被排除在考虑之外。 async 函数是 Promise 的一个实例。鉴于要求async/await 是一个可行的解决方案。

console.log((async() => void 0)() instanceof Promise);

const fn = async() => {
  let order = 0
  const promiseTree = name =>
    new Promise(res => res(`${name} order:${order++}`))

  const res = [await promiseTree('root'), [
    await promiseTree('child'), [
      await promiseTree('grandchild'), [
        await promiseTree('great grandchild sibling 1')
      , await promiseTree('great grandchild sibling 2')
      ]
    ]
  ]];
  return res;
}

fn()
.then(console.log)

【讨论】:

  • 不想使用await的原因是它会增加使用的复杂性。我创建了一个具有不同类型的节点树,通过将不同的节点拼凑在一起来构建站点的功能,例如,一个是可用于页面的路由或条件功能的谓词,一个是模块的外壳,一个是是一种与 DOM 交互的插件类型。我正在从最终用户那里抽象出承诺,所以公共 api 只是new Module([ new Module([ new Plugin() ]), new Plugin() ]) 他们只是创建了一个具有他们需要的功能的树结构
  • 这是我关于代码审查的问题的链接。通过一个 api 示例,可以更深入地了解问题和我选择的原因。 codereview.stackexchange.com/questions/211018/…
  • @synthet1c async/await 从这里的角度降低了代码的复杂性。正如代码审查答案中的代码所指出的,可以以函数方式创建嵌套数组结构。在任一问题的代码中使用的模式都存在首先执行最里面的函数的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多