从javascript中的回调中获取两个值

bot*_*aio 0 javascript

我必须调用两个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对于两个执行路径都将传递空检查,并且永远不会设置第二个值).

T.J*_*der 6

这实际上与线程无关(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)

这假设callFirstApicallSecondApi返回承诺.如果他们不这样做,你可以保证 - 如果他们:

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数组中按顺序给出结果.

  • @TJCrowder你抓住了我要求的实际东西.我不关心api调用的顺序是什么,因为它们是独立的.在这种情况下,我甚至不介意结果数组是否与promises的顺序不匹配.我必须快速解决这个问题,所以我提出了我的第一个解决方案,但我知道我遗漏了一些关于JS的东西将来会让我的生活变得更轻松.实际上,您向我展示了如何进行独立的异步调用. (2认同)