服务器回调发生4次而不是1次

时间:2014-10-18 11:10:10

标签: dart dart-html dart-async

我注意到下面的问题发生在执行我对服务器的调用时,这里的错误是什么!

 getItems(){
    print('getItems');
    request = new HttpRequest();
    request.onReadyStateChange.listen(onData_getItems);

    request.open('POST', host+'/getItems');
    request.send(' ');  
}

onData_getItems(_){
   print('call');  // --> printed 4 times!!

if (request.readyState == HttpRequest.DONE && request.status == 200) { 
    print('Data loaded successfully..';

    print(request.responseText);   // --> printed 1 time!!
    for(Map item in JSON.decode(request.responseText)){
         LineItem..children.add(new OptionElement(value: item['Code'], data: item['Name']));
    }         
} 
else if (request.readyState == HttpRequest.DONE &&
  request.status == 0) { 
     print("could not connect to server, contact your admin");  
}
else print('something else');    // --> printed 3 times

}

以上是在我的自定义元素中执行的:

class getPurchaseLines extends HtmlElement {
    static final tag = 'get-POlines';
    factory getPurchaseLines() => new Element.tag(tag);

    var shadow, LineItem, LineQty, Lineprice, clsBtn;

    getPurchaseLines.created() : super.created() {    
          shadow = this.createShadowRoot();      

         LineItem = new SelectElement()
               ..children.add(new OptionElement(value: '0', data:'Stock Code'));

          LineQty = new InputElement()..type='number'..placeholder='Qty'..style.width='50px';   
          Lineprice = new InputElement()..type='number'..placeholder='price'..style.width='50px';

          LineQty.onKeyUp.listen((e){if(LineQty.checkValidity() == false)LineQty.value='0';});
          Lineprice.onKeyUp.listen((e){if(Lineprice.checkValidity() == false)Lineprice.value='0';});

   shadow.host
            ..style.position='relative'
            ..style.display='inline-block'
            ..style.verticalAlign = 'top'
            ..style.backgroundColor = '#ffffff'
            ..style.boxShadow = '1px 1px 5px #333333'
            ..style.boxSizing = 'border-box'
            ..style.marginTop='2px'
            ..style.padding = '4px'
            ..style.paddingRight='30px'
            ..style.borderRadius='2px'
            ..style.fontSize='14px'  
            ..style.transition = 'all 0.2s ease-in'; 
   clsBtn
       ..onClick.listen((e)=> this.remove())
       ..style.position='absolute'
       ..style.right = '5px'
       ..style.top = '5px'
       ..style.color = 'black'
       ..style.cursor = 'pointer'
       ..style.zIndex = '1'
       ..style.fontSize = '16px'
       ..style.fontWeight = 'solid'  
       ..classes.add('ion-close-circled')
       ..text='x'
       ;

    shadow.nodes..add(LineItem)..add(LineQty)..add(Lineprice)..add(clsBtn);
   }

在我的函数中调用如下:

   Future fonixFuture() => new Future.value(true);                 
       for (var line in orderLines){               
               fonixFuture()
                     .then((_)=> LineDisplay = new getPurchaseLines())
                     .then((_)=> LineDisplay.getItems())
                     .then((_)=> this.parent.nodes.add(LineDisplay))
                     .then((_)=>print(this.parent.nodes));
            }

并且只有最后一个元素(LineDisplay)显示正确的getItem()结果。例如,如果我有4行,LineDisplay是:

  1. 打印"打电话"在counsle中有16次
  2. 在浏览器中显示元素LineDisplay 4次
  3. 第一个3' LineDisplay'中的项目字段为null,而最后一个显示正确执行的项目。
  4. 附上该问题的插图。

    issue illustration

    更新

    收到答案后,4个响应问题已经修复,但仍然只在最后一个元素中收到输出!更新的代码是:

        return Future.forEach(orderLines, (ol) {
             return fonixFuture()
                 .then((_)=>print(ol))
                 .then((_)=> LineDisplay = new getPurchaseLines())
                 .then((_)=> LineDisplay..getItems())
                 .then((_)=> this.parent.nodes.add(LineDisplay))
                 .then((_)=>print(this.parent.nodes));      
             });
    

    自定义元素是:

    part of fonix_client_library;
    
    class getPurchaseLines extends HtmlElement {
      static final tag = 'get-POlines';
      factory getPurchaseLines() => new Element.tag(tag);
    
      var shadow, LineItem, LineQty, Lineprice;
    
      getPurchaseLines.created() : super.created() {    
          shadow = this.createShadowRoot();      
          LineItem = new SelectElement()
            ..children.add(new OptionElement(value: '0', data:'Stock Code'));
    
          LineQty = new InputElement()..type='number'..placeholder='Qty'..style.width='50px';   
          Lineprice = new InputElement()..type='number'..placeholder='price'..style.width='50px';
    
          LineQty.onKeyUp.listen((e){if(LineQty.checkValidity() == false)LineQty.value='0';});
          Lineprice.onKeyUp.listen((e){if(Lineprice.checkValidity() == false)Lineprice.value='0';});
    
          shadow.host
                ..style.position='relative'
                ..style.display='inline-block'
                ..style.verticalAlign = 'top'
                ..style.backgroundColor = '#ffffff'
                ..style.boxShadow = '1px 1px 5px #333333'
                ..style.boxSizing = 'border-box'
                ..style.marginTop='2px'
                ..style.padding = '4px'
                ..style.paddingRight='30px'
                ..style.borderRadius='2px'
                ..style.fontSize='14px'  
                ..style.transition = 'all 0.2s ease-in'; 
       shadow.nodes..add(LineItem)..add(LineQty)..add(Lineprice);  
      }
    
     getItems(){
       print('getItems');
       request = new HttpRequest();
       request.onReadyStateChange.listen(onData_getItems);
    
       request.open('POST', host+'/getItems');
       request.send(' '); 
     }
    
     onData_getItems(_){
        if (request.readyState != HttpRequest.DONE) return;
        else
          print('responce recieved..: ${request.responseText}');
    
        if (request.readyState == HttpRequest.DONE && request.status == 200) { 
          fonixFooter.innerHtml='Items retreived..';
    
          print('responce after checking ifItemsretrieved..: ${request.responseText}');
    
              for(Map item in JSON.decode(request.responseText)){
                     LineItem..children.add(new OptionElement(value: item['Code'], data: item['Name']));
    
              }
    
    } 
       else if (request.readyState == HttpRequest.DONE &&
      request.status == 0) { 
        print('no server..');
      }
      } 
    }
    

    第二次屏幕拍摄显示更新的输出 illustration 2

1 个答案:

答案 0 :(得分:2)

你听一个流,预计会有不止一个事件。

http://www.w3schools.com/jsref/prop_doc_readystate.asp

此属性返回以下四个值之一:

  • 未初始化 - 尚未开始加载
  • loading - 正在加载
  • interactive - 已加载足够且用户可以与之交互
  • 完成 - 满载

如果您对uninitializedloadinginteractive不感兴趣,可以查看

onData_getItems(_){
  if (request.readyState != HttpRequest.DONE) return;
  print('call');  // --> printed 1 time

更新(第2期)

forEach中执行异步功能并不像您预期​​的那样工作

而不是

for (var line in orderLines){ 

使用

return Future.forEach(orderlines, (ol) {
    return fonixFuture()
    .then((_)=> LineDisplay = new getPurchaseLines())
    .then((_)=> LineDisplay.getItems())
    .then((_)=> this.parent.nodes.add(LineDisplay))
    .then((_)=>print(this.parent.nodes));      
});

在没有明显原因的情况下人为地引入异步执行看起来有点奇怪

Future fonixFuture() => new Future.value(true);

因此,我很难说出如何将上述代码段集成到您的应用代码中。
如果问题仍然存在,我建议您创建一个新问题。

更新

return Future.forEach(orderLines, (ol) {
  print(ol);
  LineDisplay = new getPurchaseLines();
  return LineDisplay.getItems()
  .then((success) {
    if(success) {
      parent.nodes.add(LineDisplay);
      print(this.parent.nodes);      
    } else {
      print('getItems() failed!');
    } // <== added
  });
});


Future getItems(){
  print('getItems');
  request = new HttpRequest();
  Completer completer = new Completer();
  request.onReadyStateChange.listen((_) => onData_getItems(completer)); // <== changed

  request.open('POST', host+'/getItems');
  request.send(' '); 
  return completer.future;
}

onData_getItems(Completer completer) {
  if (request.readyState != HttpRequest.DONE) {
    return;
  } else {
    print('responce recieved..: ${request.responseText}');
  }

  if (request.status == 200) { 
    fonixFooter.innerHtml='Items retreived..';

    print('responce after checking ifItemsretrieved..: ${request.responseText}');
    for(Map item in JSON.decode(request.responseText)){
      LineItem..children.add(new OptionElement(value: item['Code'], data: item['Name']));
    }
    completer.complete(true);
  } else if (request.readyState == HttpRequest.DONE && request.status == 0) { 
    print('no server..');
    completer.complete(false);
    // or completer.completeError('failed');
  }
}