Javascript - 一个函数首先依赖于其他函数 运行

Javascript - one function is dependent on others running first

免责声明:我主要在 Python 工作,我很确定我的问题与我对 Javascript 的异步性质的根本误解有关。如果是这样,非常感谢任何解释。

无论哪种方式,我的具体问题是使用 plotly 和 d3 从 csv 加载数据然后绘制它。这是一个示例 csv(在我的代码中称为 "fake_data.csv")

x,y,z
0.0,0.0,5.4
0.0,2.1,4.1
3.2,1.5,3.2

我有一个 index.html 像这样:

<head>
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
    <div id="graph" style="width:100%;height:100%"></div>
    <script src="scatter.js"></script>        
</body>

然后我有我的 scatter.js 脚本,它调用。它以一个简单的辅助函数开始,用于解压 csv:

function unpack(rows, key) {
    return rows.map(function(row) 
        { return row[key]; }); 
}

对于绘图功能,如果我这样做就可以正常工作:

Plotly.d3.csv('fake_data.csv', function(err, rows){
    var x = unpack(rows , 'x');
    var y = unpack(rows , 'y');
    var z = unpack(rows , 'z');
    Plotly.plot('graph', [
      {
              type: 'scatter3d',
              mode: 'lines',
              x: x,
              y: y,
              z: z
    }], {
      height: 640
    });
});

但我需要能够加载多个 csv,以便将所有必要的信息都添加到绘图中。所以我尝试将其包装在两个函数中,并像这样调用它们:

var x;
var y;
var z;
function getData(filename) {
    Plotly.d3.csv(filename, function(err, rows){
        x = unpack(rows , 'x');
        y = unpack(rows , 'y');
        z = unpack(rows , 'z'); 
    });
}

function makePlot() {
    console.log(x)
    Plotly.plot('graph', [
      {
              type: 'scatter3d',
              mode: 'markers',
              x: x,
              y: y,
              z: z
    }], {
      height: 640
    });
}

getData('fake_data.csv');
makePlot();

这什么也没有呈现。 makePlot() 里面的 console.log(x) 打印 undefined.

但是 当我在控制台中键入 makePlot() 时(我正在使用 Chrome 开发人员工具)页面加载后,它工作了!那我做错了什么?我的猜测是 makePlot() 被称为 "before" getData() 所以 x 还没有值。但是我想不出正确的方法来告诉 Javascript 调用一个函数 然后 在它之后调用另一个函数。

在此先感谢您的任何建议。这感觉像是一个非常基本的概念,我只是在用头撞墙。

D3 使用旧式回调方法。 所以你可以做那个模型,或者用 Promise 包装。

var x;
var y;
var z;

function getData(filename, resolve, reject) {
  if (!reject) reject = (err) => console.log(err);
  return new Promise((resolve, reject) => {
    Plotly.d3.csv(filename, function(err, rows) {
      x = unpack(rows, 'x');
      y = unpack(rows, 'y');
      z = unpack(rows, 'z');
      // if error
      reject(err);
      // resolve here
      resolve();
    });
  });
}

function makePlot() {
  console.log(x)
  Plotly.plot('graph', [{
    type: 'scatter3d',
    mode: 'markers',
    x: x,
    y: y,
    z: z
  }], {
    height: 640
  });
}

getData('fake_data.csv', makePlot);

只是为了补充 的回答:如果您确切知道要下载哪些 csv 文件以执行 makePlot(),您可以简单地使用 Promise.all 来确保所有文件都在之前显示密谋。

var x;
var y;
var z;

function getData(filename, resolve, reject) {
  if (!reject) reject = (err) => console.log(err);
  return new Promise((resolve, reject) => {
    Plotly.d3.csv(filename, function(err, rows) {
      x = unpack(rows, 'x');
      y = unpack(rows, 'y');
      z = unpack(rows, 'z');
      // if error
      if (err instanceof Error) {
        reject(err);
      } else {
        // resolve here
        resolve(true); // return true to check resolve status
      }
    });
  });
}

function makePlot() {
  console.log(x)
  Plotly.plot('graph', [{
    type: 'scatter3d',
    mode: 'markers',
    x: x,
    y: y,
    z: z
  }], {
    height: 640
  });
}

var promise1 = getData('fake_data.csv');
var promise2 = getData('fake_data2.csv');
var promise3 = getData('fake_data3.csv');

Promise.all([
  promise1,
  promise2,
  promise3
]).then(function(values) {
  // check if all promises are resolved
  if (values.every(function(value) { return value == true })) {
    makePlot();
  }
})