我必须调用两个API来获取一些值.然后我能够将结果呈现给用户.我通过回调进行顺序调用实现了这一点:
function firstApi() {
callFirstApi(function(firstValue) {
secondApi(firstValue);
});
}
function secondApi(firstValue) {
callSecondApi(function(secondValue) {
presentResults(firstValue, secondValue);
});
}
function presentResults(firstValue, secondValue) {
// do something...
}
Run Code Online (Sandbox Code Playgroud)
困扰我的问题是API调用可能是异步的.我想知道这种解决方案是否有任何问题:
var firstValue = null;
var secondValue = null;
function apiResult(value) {
if (firstValue === null) {
firstValue = value;
return;
}
secondValue = value;
presentResults();
}
function presentResults() {
// do something...
}
firstApiCall(apiResult);
secondApiCall(apiResult);
Run Code Online (Sandbox Code Playgroud)
JavaScript是单线程的,但我仍然不确定上下文切换可能发生的位置.换句话说,如果异步调用完成时有可能在执行过程中中断函数调用(因此,例如,firstValue对于两个执行路径都将传递空检查,并且永远不会设置第二个值).
这实际上与线程无关(JavaScript不是单线程的,甚至不是在浏览器上,但除非你专门创建新线程,否则你只处理一个),只是异步性.
如果我正确阅读,你说你要打电话callFirstApi,打电话callSecondApi,当两个操作完成后你想打电话presentResults.您不需要对API进行串行调用(一个接一个),如果它们并行(两者同时运行)就没问题,您只需要等待它们两个完成(无论如何)完成顺序)
您的解决方案不会(因为你怀疑)的工作,因为结果进来可能不符合你要求的顺序,但这种解决方案假定它们的顺序做你调用的顺序完成callFirstApi,callSecondApi.您需要一个不假设第一个在第二个之前完成的假设的解决方案.
编写异步操作的这个问题是开发承诺的关键动机之一,这些承诺在ES2015(又名ES6)及更高版本中是原生的,并且可以与polyfill库一起使用.当你需要在系列中做一些异步的事情(彼此另一个)时,你会使用一个承诺链; 当你需要并行处理时(它们可以重叠,你只想等到它们全部完成),你就可以启动它们并Promise.all等待它们全部完成.
使用promises的示例如下所示:
Promise.all([callFirstApi(), callSecondApi()])
.then(function(results) {
// results[0] is the result from the first, results[1] is the result from the second
presentResults(results[0], results[1]);
})
.catch(function() {
// an error occurred in one of the calls
});
Run Code Online (Sandbox Code Playgroud)
这假设callFirstApi并callSecondApi返回承诺.如果他们不这样做,你可以保证 - 如果他们:
function promisify(f) {
return function() {
return new Promise(function(resolve, reject) {
f(function(result) {
if (/*...result is an error...*/) {
reject(/*...error here...*/);
} else {
resolve(/*...result here...*/);
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
(这很简单,但你明白了.)
然后:
// Once:
var firstApiWithPromises = promisify(callFirstApi);
var secondApiWithPromises = promisify(callSecondApi);
// As needed:
Promise.all([firstApiWithPromises(), secondApiWithPromises()])
.then(function(results) {
presentResults(results[0], results[1]);
})
.catch(function() {
// an error occurred in one of the calls
});
Run Code Online (Sandbox Code Playgroud)
它们完成的顺序无关紧要,上面将在继续之前等待两者,并在results数组中按顺序给出结果.