1

我遇到了 Futures 的以下示例(下面的示例 1),这让我想知道我是否可以改变处理 Futures 的方式并删除所有保留处理顺序的嵌套函数调用,但这会导致我发现缩进有点乱。

但是,我的程序的更改版本不起作用。它没有保留处理顺序,也没有“等待”函数完成。例如,在从第一次调用 (fGetUserInput) 返回之前,调用了另一个后续函数。

为什么在示例 1 中,所有“1st level”“new Future”都是按顺序处理的,而在示例 2 中,我更改的代码中,处理顺序没有保留。在处理对 fGetUserInput 的调用时,是否处理其后的 Futures 之一?

是不是因为所有的语句都是同步的,所以“示例 1”才“有效”?

我遇到了对“runAsync”的引用。可以用来实现我想要的吗?(按顺序处理,没有所有缩进)。

    // Example 1. Code that I encountered  for Futures //

import 'dart:async';

main() {

  new Future(() => print('1'))
   .then((_) => print('a'))
   .then((_) => print('b'));

  new Future(() => print('2'))
   .then((_) => print('c'))
   .then((_) => print('d'));

  new Future(() => print('3'))
   .then((_) => 
       new Future(() => print('e'))
       .then((_) => print('f'))
   );

  new Future(() => print('4'))
   .then((_) => 
       new Future(() => print('g'))
       .then((_) => print('d'))
   );
}

以上结果导致以下控制台输出顺序:-

1 ab 2 cd 3 4 efgd

我认为这是有道理的。

因此,我修改了我的代码以对其进行如下测试:-

   // Example 2. Altered version of my code which //
   // does not preserve the order of processing,  //
   // which is necessary for program to function. //

  new async.Future(() => fGetUserInput())
  .then((lInput) {
    iMaxIters = int.parse(lInput[4]);
    tClearTable = (lInput[5] == "y");

    iDivisor = fInitialize(iMaxIters);

    tgPrint = false;  // printing off

    sUri =
     "postgres://${lInput[1]}:${lInput[2]}@localhost:5432/${lInput[3]}";
    sStartTime = lInput[7];
  })
  .catchError((oError) => fFatal("Get User Input", oError));

  new async.Future(() => fConnectToDb(sUri, sStartTime))
  .then((bool tConnected) {
    if (ogDb == null)
      fFatal("Unable to connect to database", "");
    print ("Processing database ......");
  })
  .catchError((oError) => fFatal("Connect to Db", oError));

  new async.Future(() => fClearTable(tClearTable))
  .then((sResult) => print (sResult+"\n"))
  .catchError((oError) => fFatal("Clear Table", oError)); 

  new async.Future(() => fProcessInserts(iMaxIters, iDivisor))
  .then((sResult) => print (""))
  .catchError((oError) => fFatal("Process Inserts", oError));

  new async.Future(() => fSetupRandKeys())
  .then((sResult) => print (""))
  .catchError((oError) => fFatal("Setup Random Keys", oError));

  new async.Future(() => fProcessUpdates(iMaxIters, iDivisor))
  .then((sResult) {
    String sTotValue = fFormatAmount(igGrandTotAmt, true, 2);
    fPrint ("Grand Total added to database = \$${sTotValue}");
    ogDb.close();
    exit(0);
  })
  .catchError((oError) => fFatal("Process Updates", oError));
}  

void fFatal (String sMessage, Error oError) {
  print("\n\nFatal Error. $sMessage\n${oError}");
  exit(1);
}

async.Future<String> fProcessInserts(int iMaxIters, int iDiv) {
  async.Completer oCompleter = new async.Completer<String>();

  int iTot = 0;
  Function fLoop;

  print ("\nProcessing Inserts ......");
  fResetAndStartWatch();

以下是我在进行上述更改之前的代码,以下示例 3 似乎可以正常工作。我不喜欢缩进的程度,在有更多函数调用的情况下,这会增加缩进的程度。我希望有一种更优雅的方式来做到这一点。

    // Example 3: The original version of my code //
    // which does preserve the order of processing //
void main() {

  print("");

  String sCheckPoint = "Get User Input";
  fGetUserInput()
  .then((lInput) {
    int iMaxIters = int.parse(lInput[4]);
    bool tClearTable = (lInput[5] == "y");

    int iDiv = fInitialize(iMaxIters);

    tgPrint = false;  // printing off

    String sUri =
      "postgres://${lInput[1]}:${lInput[2]}@localhost:5432/${lInput[3]}";

    sCheckPoint = "Connect to Database";
    fConnectToDb(sUri, lInput[7]).then((bool tConnected) {
      if (ogDb == null)
        fFatal(sCheckPoint, "Unable to conenct to Db");
      print ("Processing database ......");
      sCheckPoint = "Clear Table";
      fClearTable(tClearTable).then((sResult) {
        print (sResult+"\n");
        sCheckPoint = "Process Inserts";
        fProcessInserts(iMaxIters, iDiv).then((sResult) {
          print;
          sCheckPoint = "Set-up Random Keys";
          fSetupRandKeys().then((sResult) {
            print;
            sCheckPoint = "Process Updates";
            fProcessUpdates(iMaxIters, iDiv).then((sResult) {
              String sTotValue = fFormatAmount(igGrandTotAmt, true, 2);
              fPrint ("Grand Total added to database = \$${sTotValue}");
              ogDb.close();
              exit(0);
            });
          });
        });
      });
    });
  })
  .catchError((oError) => fFatal(sCheckPoint, oError));
}

void fFatal (String sMessage, Error oError) {
  print("\n\nFatal Error. $sMessage\n${oError}");
  exit(1);
}

async.Future<String> fProcessInserts(int iMaxIters, int iDiv) {
  async.Completer oCompleter = new async.Completer<String>();

  int iTot = 0;
  Function fLoop;

  print ("Processing Inserts ......");
  fResetAndStartWatch();
4

1 回答 1

1

请记住,您可以链接期货,这将大大减少您的缩进。

缺点是您没有嵌套范围,如果您有多个值要在异步块之间传播,这可能很有用,但这可以通过几种方式解决。

这是您使用链接的示例 3:

// Example 3 with chaining
void main() {
  String checkPoint = "Get User Input";
  getUserInput().then((input) {
    int maxIters = int.parse(input[4]);
    bool clearTable = (input[5] == "y");

    int div = initialize(maxIters);

    shouldPrint = false;  // printing off

    String uri =
        "postgres://${input[1]}:${input[2]}@localhost:5432/${input[3]}";

    checkPoint = "Connect to Database";
    return connectToDb(uri, input[7]).then((bool connected) {
      if (db == null)
          fatal(checkPoint, "Unable to conenct to Db");
      print ("Processing database ......");
      checkPoint = "Clear Table";
      return clearTable(shouldClearTable);
    }).then((result) {
      print (result+"\n");
      checkPoint = "Process Inserts";
      return processInserts(maxIters, div);
    }).then((result) {
      print('');
      checkPoint = "Set-up Random Keys";
      return setupRandKeys();
    }).then((result) {
      print('');
      checkPoint = "Process Updates";
      return processUpdates(maxIters, div);
    }).then((result) {
      String totValue = formatAmount(grandTotAmt, true, 2);
      print("Grand Total added to database = \$${totValue}");
      return db.close();
      // exit(0); pretty much never call exit()
    });
  }).catchError((error) => fatal(checkPoint, error));
}

编辑:哎呀,仔细看,我被范围问题所困扰......我添加了一个嵌套级别,只是为了在以下块可访问的范围内捕获所需的变量。我也删除了匈牙利式的符号,因为......不要在 Dart 中这样做:)

于 2013-05-25T21:22:35.510 回答