在单独的函数中使用节点中回调的结果

Using results of a callback in node in a separate function

我可能在某处漏掉了重点,所以我正在寻求建议。

我有一个 nodejs 服务器正在侦听客户端连接,并根据收到的数据调用 API。

第一次调用 API 会得到一个 ID,需要在后续调用中使用该 ID 将它们组合在一起。

我遇到的困难是对 API 的调用必然是异步的,并且在回调中我将 ID 分配给一个变量。当 API 服务器正在处理该异步调用时,更多数据来自客户端,需要进行更多 API 调用,但在我知道第一次调用的结果之前我无法触发它们因为第二次调用取决于它。

处理这个问题的正确方法是什么?我觉得我应该使用 Q 来保证第一个 API 调用的结果给第二个,但我不确定它应该如何构建。或者我应该在第一个完成之前排队 API 调用吗?我该怎么做?

示例问题代码:

var server = net.createServer();

//set up the callback handler 

server.on('connection', handleConnection);

handleConnection(conn) {
  //do some stuff...
  firstAPICall();
  conn.on('data', handleData);
}

handleData(data) {
  //do some stuff...
  otherAPIcall();
}

firstAPICall() {
  client.get("http://myAPI/getID", function (data, response) {
    conn.myID = data[0].myID;
    }
  }
}

otherAPICall() {
  //How do I make sure I actually have a value
  //in conn.myID from the first function???
  client.post("http://myAPI/storeData", { data: {myID:conn.myID, data:someData} }, function (data, response) {
    //do some stuff...
    }
  }
}

尝试使用承诺。然后使用 'then' 调用 otherAPICall()

我想你可以假设他们会在连接后立即发送数据。因此,如果您有 ID,您可以简化并仅签入 otherAPICall,如果没有,则可以使用回调。 Promises 或 async/await 关键字可能会使事情变得更好,但这不是必需的。

var server = net.createServer();

//set up the callback handler 

server.on('connection', handleConnection);

handleConnection(conn) {
  conn.on('data', handleData(connm, data));
}

handleData(conn, data) {
  //do some stuff...
  otherAPIcall(conn);
}

checkID(conn, cb) {
  if (!conn.myID) {
    client.get("http://myAPI/getID", function (data, response) {
      conn.myID = data[0].myID;
      cb();
    });
  } else {
    cb();
  }
}

otherAPICall(conn) {
  checkID(conn, function() {
    client.post("http://myAPI/storeData", { data: {myID:conn.myID, data:someData} }, function (data, response) {
      //do some stuff...
    });
  });
}

是的,您应该为此使用 promises。对第一次调用异步解析的id做一个promise,然后在后面的调用中使用:

handleConnection(conn) {
  //do some stuff...
  var idPromise = firstAPICall();
  conn.on('data', function handleData(data) {
    //do some stuff...
    otherAPIcall(idPromise).then(function(result) {
      …
    });
  });
}

firstAPICall() {
  return Q.Promise(function(resolve, reject) {
    client.get("http://myAPI/getID", function (data, response) {
      resolve(data[0].myID);
    });
  });
}

otherAPICall(idPromise) {
  return idPromise.then(function(myID) {
    return new Promise(function(resolve, reject) {
      client.post("http://myAPI/storeData", {
        data: {myID:myID, data:someData}
      }, function (data, response) {
        //do some stuff...
        resolve(…);
      });
    });
  });
}

可能您应该考虑在额外函数中为 client.get 调用的结果创建承诺。还要确保在那里正确处理错误并用它们调用 reject 。如果 client 会使用节点回调约定,Q 甚至有 some nice helper functions

promises 可以链接值,并且总是在回调发生后用返回值解析,

function async(value) { 
var deferred = $q.defer();
var asyncCalculation = value / 2;
deferred.resolve(asyncCalculation);
return deferred.promise;
}

var promise = async(8) 
.then(function(x) {
    return x+1;
})
.then(function(x) {
    return x*2;
})
.then(function(x) {
    return x-1;
});
promise.then(function(x) { 
console.log(x);
});

此值通过所有成功回调,因此记录值 9 ((8 / 2 + 1) * 2 - 1)。