【问题标题】:How to enforce promise in array loop如何在数组循环中强制执行承诺
【发布时间】:2019-08-31 13:31:05
【问题描述】:

我正在尝试了解如何在给定的数组循环中实现 Promise 和 Promise.All 的基础知识,例如,从可以在循环中执行任意数量的操作的 firebase 查询中,然后我可以访问到后来的结果。我似乎无法获得正确的语法和逻辑。下面是一个示例方法,我想延迟将一些项目插入数组,然后在循环后访问数组进行处理。

我在 Stackoverflow 上研究了不同的方法。有些人分配了一个 promises = snap.forEach 循环,然后在完成后以某种方式解决这个问题。其他人正在循环内创建一个承诺。在下面的示例中,我只是使用 settimeout 来延迟/创建异步进程。

        testfirebaseData = () => {

        let channels =[];
        var promises=[];
         firebase.database().ref('challengeResponses').child(day).once('value', snap => {

          snap.forEach(channelChild => {

                promises.push(new Promise((resolve) => {
                    setTimeout(() => {
                    channels.push(channelChild.key);
                    resolve(channels)
                   },1000)
                })
                )

             })             
        }).then (() => {
         Promise.all(promises).then(() => {
            console.log(channels[0])
        })

       }


    }

我希望上面的输出显示“通道”数组中的第一个元素,但它总是以“未定义”返回......因为我显然没有正确处理承诺。我错过了什么?

【问题讨论】:

  • 你能分享一个简单的例子吗?我试过设置 promises = fiirebase.database() ...但也无法让它工作。我需要在回调中解决吗?

标签: javascript firebase promise


【解决方案1】:

这是使用您的代码样式的示例示例。我放的是数字而不是数组中的对象;

https://jsfiddle.net/th3vecmg/4/

 var promises = [];
 let channels =[];

 [1, 2, 3, 4, 5].forEach((elm, i) => {

   promises.push(new Promise((resolve) => {
     setTimeout(() => {
      channels.push(elm)
       resolve(elm);
     },  1000)
   }))

 });
 console.log(channels[0]) // gives undefined
 Promise.all(promises).then(() => {
   console.log(channels[0]) // gives 1
 })

您不应该在 then 中得到未定义,因为它正在等待执行承诺。如果您试图在 then 范围之外显示结果

,您只会得到未定义的结果

代码没有真正意义,因为您在 then 中显示一个全局变量,而不是依赖于 promise 的输出

如果你想延迟执行 1 然后在 setTimeout 的 timeArgument 中做一些乘法...

【讨论】:

  • Stange,我复制/粘贴了您的代码并尝试过...有时结果为 1,有时结果为 5?不知道为什么会不一致?更重要的是,我在我的代码中实现了相同的逻辑(保持我的 firebase 查询/循环 foreach)并且它不起作用......即使将它放在 then() 块中,它也总是返回“未定义”,我将更新我的问题以包含我正在尝试的确切代码。
  • 如果你愿意,检查小提琴的例子,它总是返回第一个元素,但我想你现在已经解决了你的问题......
【解决方案2】:

您的 new Promise(...) 应该包装 firebase 调用,因为那是异步操作。并且不在回调中。回调内部没有异步操作,只是普通数组推送,这是一个同步操作

var promise = new Promise((resolve)=>{
   firebase.database().ref('challengeResponses').child(day).once('value', snap => {
     var channels=[];
     snap.forEach(channelChild => {
       channels.push(channelChild.key);
     });
     resolve(channels);
   });
});

promise.then((channels)=>{
    console.log(channels);
});

如果您想延迟整个操作:

var promise = new Promise((resolve)=>{
   firebase.database().ref('challengeResponses').child(day).once('value', snap => {
     var channels=[];
     setTimeout(()=>{
       snap.forEach(channelChild => {
         channels.push(channelChild.key);
       });
       resolve(channels);
     },1000);
   });
});

要模拟嵌套的异步操作,您可以像以前一样将 Promise 添加到数组中,但在外部 Promise 中解析 Promises.all() 并在内部 Promise 中解析您的数据:

var promise = new Promise((resolve)=>{
   firebase.database().ref('challengeResponses').child(day).once('value', snap => {
      var snapPromises=[];
      snap.forEach(channelChild => {
         snapPromises.push(new Promise((snapresolve)=>{
           setTimeout(()=>{
             snapresolve(channelChild.key);
           },1000)
         });
      });
      resolve(Promise.all(snapPromises));         
   });
});

【讨论】:

  • 谢谢,但我想使用 settimeout 来延迟处理,看看会发生什么。如果您使用您的代码,但将数组 push 放在 settimeout 中,例如 setTimeout(() => { channels.push(channelChild.key) }, 1000); ...它以“未定义”返回。为什么?
  • 因为 setTimeout 也是一个异步操作,所以它里面的代码在原始承诺完成之前不会运行。如果您想延迟整个操作,请将 forEach() / resolve 调用放在 setTimeout 中。如果你想延迟 forEach 的每次迭代,你需要改变你的代码,因为 forEach 不使用或等待承诺
  • 不能将 settimeout 放入 promise 中吗?此时,我们将收集所有这些 p;romise 并使用 Promise.All(promises) 来执行 console.log?我试图使用 settimeout 来模拟将在 foreach 循环中的其他异步逻辑
  • 查看最新编辑以查看模拟嵌套异步操作
  • 谢谢,这就是我想要的。 firebase 调用已经返回了一个 Promise,所以我只需要在这个逻辑中添加一个 .then(),然后调用 Promise.all()。感谢您的反馈!
猜你喜欢
  • 2017-08-05
  • 2020-05-15
  • 1970-01-01
  • 2018-10-13
  • 2016-08-25
  • 2016-12-02
  • 1970-01-01
  • 2018-12-24
  • 2014-03-20
相关资源
最近更新 更多