0

我正在尝试编写一个脚本来顺序地从具有 Web 界面的打印机中提取数据。大型本地网络上有 500 多个,因此我想在前一个返回(成功与否)后呼叫下一个。我很难将我的头脑围绕回调......如果这是最好的解决方案。

这是我目前的立场(友善,这是我对 jQuery/Javascript 的介绍,这是一个证明测试)。另外,有没有办法从结果调用中构建一个数组?我转向 Javascript 的原因是我无法让 PHP 与执行时间一致。

哦,你会在下面看到 ASYNC: true 只是因为我尝试了 w/false 并且它不起作用(返回任何东西)。

function pingDevice(prnList) {
    prnList = ["www.google.com", "amazon.com", "facebook.com", "as923f.com"];
    document.getElementById("myDiv").innerHTML="please wait...";

    $(prnList).each( function(index,printer) {
        $.ajax({
            type: "GET",
            dataType: "html",
            url: "pingTest.php?ping="+printer,
            async: true,
            success: function (data) {
                $('#myDiv').append( $('<div class="prn"></div>').html(data) );
                $prnResults[printer] = data;
            },
            error: function () {
                $prnResults[printer] = data;
            }
        });
    });
    $('#myDiv').append( $('<div class="prn"></div>').$prnResults );
}
4

2 回答 2

0

看起来您希望您的代码做两件事。

  1. 仅在对上一个打印机的请求返回时才为下一个打印机请求数据
  2. 只有在所有请求都返回后才更新 DOM。

不幸的是,您拥有的代码都没有做这些事情。:(

$.each是一种迭代类似数组的东西的方法,但它不会等到请求返回后再继续列表中的下一个项目。ajax 请求是异步发生的,这意味着您调用它们并继续代码中的下一个操作。当它们完成后,它们将回调successorerror函数,但是当请求发生时,这段代码永远不会阻塞。

如果你想触发顺序请求,你可以创建某种帮助函数,让你循环遍历一个数组,并且只有在你知道你完成了第一个元素时才调用数组中的下一个元素的函数。如果您想在它们全部完成时执行一些操作,那么您需要一个函数,它在数组中的所有项目都完成处理时回调。

这是一个关于如何按顺序执行异步操作的小示例。

var data = ['1', '2', '3', '4'];

function doAsnycStuffSequentially(data, callback, final) {
  var i = 0,
      length = data.length;

  function getNextItem() {
    callback(data[i++], done);
  }

  function done(err) {
    if (err) {
      return final(err);
    }

    // Only call the final function if there is an error or if we are done looping.
    if (i >= data.length) {
      return final();
    }

    getNextItem();
  }

  getNextItem();
}

doAsyncStuffSequentially(data, function(item, done) {
  console.log("item is ", item);
  // simulate some asynchronous operation
  setTimeout(done, 1000);
}, function(err) {
  console.log("done with all and error is", err);
});

要将此模式应用于您自己的代码,您只需定义自己的回调函数,该函数会在数组中的每个项目上调用,如下所示:

var printerData = {},
    printerNames = ['hurp', 'durp'];

function getPrinterInfo(printerName, done) {
  $.ajax({
      type: "GET",
      dataType: "html",
      url: "pingTest.php?ping="+printer,
      success: function (data) {
        printerData[printerName] = data;
        done();
      },
      error: function (jqXHR, textStatus, err) {
        console.error("error getting printer status", err);
        done(err);
      }
  });
}

doAsyncStuffSequentially(printerName, getPrinterInfo, function(err) {
  console.log("done getting printer names and error was", err);
  console.log("printerData is", printerData);
});

关键是您在and回调中调用该done函数。这向函数发出一个异步操作已完成的信号,如果我们完成或发生错误,它应该启动下一个操作或调用该函数。successerrordoAsyncStuffSequentiallyfinal

于 2012-11-13T22:14:42.253 回答
0

虽然我同意 Sonesh 的观点,即服务器端的东西可能更适合这项任务,但这里有一些对你的代码应该有效的调整(未经测试)。

基本上,将实际的 ajax 调用嵌套在它自己的函数pingNext中。每次调用返回时,都会为prnList数组中的下一项再次调用该函数。此外,我调整了代码以使用 jQuery 的类似Promise 的语法进行 ajax 调用。一般来说,它是一种更好的链接 ajax 调用的语法(尽管在这里不是完全必要的)

function pingDevice(prnList) {
  prnList = ["www.google.com", "amazon.com", "facebook.com", "as923f.com"];
  document.getElementById("myDiv").innerHTML="please wait...";

  var i = 0;
  function pingNext(j) {
    $.ajax({
        type: "GET",
        dataType: "html",
        url: "pingTest.php?ping="+prnList[j],
        async: true,
    }).done(function(data) {
      // stuff to do when successfull
      $('#myDiv').append( $('<div class="prn"></div>').html(data) );
    }).fail(function(data) {
      // stuff to do on error
    }).always(function(data){
      // stuff to do no matter what

      // stash the result
      $prnResults[printer] = data;

      // if there are more items in the prnList array, repeat
      if (i < prnList.length) {
        i++;
        pingNext(i);
      }
    });
  }
}
于 2012-11-13T22:30:45.377 回答