This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
                            
                                (6个答案)
                            
                    
                2年前关闭。
        

    

函数v1执行w / o错误,并且控制台日志显示了填充有响应数据的预期数组。但是,我试图通过将nysQueryReturn中的2个数组作为对象返回来简化生活。

功能v2也可以无错误执行,但控制台日志显示
nysQueryReturn {sldlBills: Array(0), slduBills: Array(0)}
...empty arrays.

Function v1: works as expected

function getBillData() {
  return getBills().
  then(function(response) {
    // save retrieved bill numbers
    var billData = response;
    var nysQueryReturn = [];

    // get NY State Leg data for each bill number
    billData.forEach(function(p) {

      // Assembly bill
      nysBillQuery(p.gsx$sessionyear.$t, p.gsx$assemblynum.$t).
      then(function(response){
        nysQueryReturn.push(response);
      });

      // Senate bill
      nysBillQuery(p.gsx$sessionyear.$t, p.gsx$senatenum.$t).
      then(function(response){
        nysQueryReturn.push(response);
      });
    });
    console.log('nysQueryReturn', nysQueryReturn);
    return nysQueryReturn;
  });
} // end of getBillData()


函数v2:空数组:(

function getBillData() {
  return getBills().
  then(function(response) {
    // save retrieved bill numbers
    var billData = response;
    var nysQueryReturn = {
      sldlBills: [],
      slduBills: []
    };

    // get NY State Leg data for each bill number
    billData.forEach(function(p) {

      // Assembly bill
      nysBillQuery(p.gsx$sessionyear.$t, p.gsx$assemblynum.$t).
      then(function(response){
        nysQueryReturn.sldlBills.push(response);
      });

      // Senate bill
      nysBillQuery(p.gsx$sessionyear.$t, p.gsx$senatenum.$t).
      then(function(response){
        nysQueryReturn.slduBills.push(response);
      });
    });
    console.log('nysQueryReturn', nysQueryReturn);
    return nysQueryReturn;
  });
} // end of getBillData()


我在stackoverflow上找到了"array of arrays""array of objects"的几个示例,但是我看不到如何重新调整这些答案的大小以适合我的“数组对象”方案。我所缺少的任何想法/指针/解释都将受到热烈欢迎。

感谢您的时间。

编辑:

k,我发现this question & answer,这似乎表明我“做对了”。换个角度看,Chrome Dev Tools控制台报告这两个阵列为“空”,但展开时它们包含预期的信息。尽管如此,我实际上无法在不获取nysQueryReturn.sldlBills[0].basePrintNo的情况下访问带有TypeError: Cannot read property 'basePrintNo' of undefined的数组元素,并且我无法终生弄清楚为什么。

我没有得到什么?

最佳答案

我假设您了解arrow functions以及如何正确使用它们。我还将假设您了解letconst。这些都不是必需的,它们只是使事情变得更漂亮。您可以将所有箭头功能(在下面的示例中)替换为普通功能,并将所有letconst声明替换为var声明。

您的最终结果应类似于以下内容:

function getBillData() {
  return getBills().then((billData) => {
    const nysQueryReturn = {
      sldlBills: [],
      slduBills: []
    };

    // This should look familiar, it returns a Promise.  This
    // Promise first loads the Assembly bill then adds the result
    // to the appropriate array in nysQueryReturn object.
    const loadAssemblyBill = (bill) => {
      return nysBillQuery(bill.gsx$sessionyear.$t, bill.gsx$assemblynum.$t).then((sldlBill) => {
        nysQueryReturn.sldlBills.push(sldlBill);
      });
    };

    // This should look familiar, it returns a Promise.  This
    // Promise first loads the Senate bill then adds the result to
    // the appropriate array in nysQueryReturn object.
    const loadSenateBill = (bill) => {
      return nysBillQuery(bill.gsx$sessionyear.$t, bill.gsx$senatenum.$t).then((slduBill) => {
        nysQueryReturn.slduBills.push(slduBill);
      });
    };

    // First exciting thing: Let's map each bill to a 2 workers
    // that will load the important information that we will add to
    // nysQueryReturn.
    const workers = [];

    billData.forEach((bill) => {
      workers.push(loadAssemblyBill(bill));
      workers.push(loadSenateBill(bill));
    });

    // Return a Promise that will wait for all the workers to
    // finish.
    return Promise.all(workers).then(() => nysQueryReturn);
  });
}


您没有看到期望的结果,因为您没有等待结果加载。实际上,如果您设置了超时并在以后的某个时间检查结果,您将看到阵列已填充。

让我们将nysQueryReturn视为一个包含所有sldlBillsslduBills,作为工作人员的Promises和作为客户的调用getBillData()的代码的框。使用getBillData()的v2,您


找到所有的账单。
创建了nysQueryReturn
雇用了一些工人,并告诉他们该怎么做。
把盒子交给你的顾客。


不幸的是,您没有等到您的工人完成工作,然后再将盒子交给客户。不用说,您的客户很困惑,只是假装他们得到了他们想要的东西。

通过新的实施,您可以


找到所有的账单。
创建了nysQueryReturn
雇用了一些工人,并告诉他们该怎么做。
等待您的工人给您他们发现的东西。
把盒子交给你的顾客。


您可以通过维护workers列表来等待工作人员完成工作,然后等待他们的all()Promise.all())告诉您他们已经完成工作并将其结果添加到nysQueryReturn框中。完成所有步骤后,即可将所有结果提供给客户(.then(() => nysQueryReturn))。

请记住,每次使用Promise(具有.then()方法的任何东西)时,您都在执行普通程序流程之外的内容。 JS将不等待该流程完成再继续其原始流程。从图片上看,这看起来像:

___________                     ____________                                ____________
|  Flow 1 |                     |  Flow 2  |                                |  Flow 3  |
-----------                     ------------                                ------------

billData.forEach(/* ... */);
console.log(/*...*/);
return nysQueryReturn;
                                nysQueryReturn.sldlBills.push(/*...*/);
                                                                            nysQueryReturn.slduBills.push(/*...*/)


要等待新流程完成,您必须通过将回调传递给.then()来显式等待它。

09-25 21:14