保存的javascript facebook API响应仍未定义?

时间:2017-11-02 12:36:22

标签: javascript asynchronous d3.js callback facebook-javascript-sdk

我怀疑这是异步问题, 我无法理解问题所在。 所以我做了多个api请求并用响应填充列表。 然后我有一个绘制数据的D3.js脚本, 虽然收到undefined,但我在这里用一个简单的日志替换它。 (当然控制台稍后会实时“评估”这些值,但是记录一个节点[0]项确实是未定义的。) 我测试了为后续脚本设置超时但无效, 自从请求以来我无法提出回调解决方案 本身就是一个回调。 (我知道forEach是在这里使用的正确方法,但我也试图通过立即返回来实现赋值功能,这也是我无法实现的功能。

variables=["pageid1","pageid2","pageid3"];
nodes=[];
variables.map(function(variable){
    FB.api("/"+variable,"GET",{fields:'name,picture.type(large),engagement'},function(response){
        if(!response.error){
            nodes.push(response);
        }
    });
});
console.log(nodes);

3 个答案:

答案 0 :(得分:3)

您可以将请求包装在承诺中。然后等待所有承诺得到解决,在这种情况下,您的节点变量将填充响应。 你可以这样做:

nodes=[];
function sendRequest( variable ) {
    return new Promise ( ( resolve, reject ) => {
        FB.api("/"+variable,"GET",{fields:'name,picture.type(large),engagement'},function(response){
           if(!response.error)
                 resolve( response );
        });
    });
}

Promise.all( variables.map(function( variable ) {
    return sendRequest( variable ); 
})).then( values => {
     /* All the responses are solved here */
     nodes = values.splice( 0 );
     console.log(  nodes );
});

答案 1 :(得分:1)

  

我怀疑它是异步性的问题

是的,当然,您的console.log可以在.api完成之前触发。试图用setTimeout延迟它只是糟糕的编程(它是一个猜谜游戏)。

nodes上的任何处理都需要在.api回调中。如果您要处理多个异步调用并且需要在处理nodes之前完成所有操作,那么您应该使用d3.queue之类的内容。来自docs(bolding mine):

  

队列使用可配置的并发性评估零个或多个延迟异步任务:您可以控制同时运行的任务数。 当所有任务完成或发生错误时,队列会将结果传递给您的等待回调。这个库类似于Async.js的并行(当并发是无限的时候),系列(当并发是1时)和队列,但是占用的空间要小得多:从版本2开始,d3-queue约为700字节gzip,相比之下4,300 for Async。

在您的情况下,代码可能如下所示(未经测试):

var q = d3.queue();

variables.forEach(function(d) {
  q.defer(FB.api, "/" + variable, , "GET", {fields: 'name,picture.type(large),engagement' });
});

q.await(function(error, response1, response2, response3) {
  if (error) throw error;
  // build out nodes from responses...
});

答案 2 :(得分:1)

使用async / await的不同方法和一些修复(let,arrow functions,...):

let variables = ['pageid1', 'pageid2', 'pageid3'];
cosnt sendRequest = (variable) => {
    return new Promise ((resolve, reject) => {
        FB.api('/' + variable, {fields:'name,picture.type(large),engagement'}, (response) => {
            if(!response.error) {
                resolve(response);
            } else {
                reject(response.error);
            }
        });
    });
};

const getData = async () => {
    let nodes = [];
    for (let i = 0; i < variables.length; i++) {
        let response = await sendRequest(variables[i]);
        nodes.push(response);
    }
    console.log(nodes);
};

getData();