2016-03-05 175 views
1

我想遞歸調用AWS的SNS listEndpointsByPlatformApplication。如果還有更多要返回(如:AWS SNS listEndpointsByPlatformApplication),則返回前100個端點,然後返回NextToken中的令牌。遞歸調用異步函數,返回一個承諾

這是我已經試過:

var getEndpoints = function(platformARN, token) { 

    return new models.sequelize.Promise(function(resolve, reject) { 
    var params = { 
     PlatformApplicationArn: platformARNDev 
    }; 
    if (token != null) { 
     params['NextToken'] = token; 
    } 
    sns.listEndpointsByPlatformApplication(params, function(err, data) { 
     if (err) { 
     return reject(err); 
     } 
     else { 
     endpoints = endpoints.concat(data.Endpoints); //save to global var 
     if ('NextToken' in data) { 
      //call recursively 
      return getEndpoints(platformARN, data.NextToken); 
     } 
     else { 
      console.log('trying to break out!'); 
      return resolve(true);   
     } 
     } 
    }); 
    }); 
} 

我與調用它:

getEndpoints(platformARNDev, null) 
.then(function(ret) { 
    console.log('HERE!'); 
}, function(err) { 
    console.log(err); 
}); 

問題是:在第一次調用發生,那麼遞歸調用發生了,我得到的消息trying to break out!,但HERE!永遠不會被調用。我想我的承諾如何迴歸,我有些不妥。

感謝指點。

回答

4

的問題是,你試圖解決/拒絕部分完成查詢。這是一個虛擬服務的完整工作示例。我incapsulated數據抓取到它自己的遞歸函數只有做好解決/拒絕時,我已經完全獲取所有數據或偶然發現了一個錯誤:

// This is the mock of the service. It yields data and token if 
// it has more data to show. Otherwise data and null as a token. 
var dummyData = [0, 1, 2, 3, 4]; 
function dummyAsyncCall(token, callback) { 
    token = token || 0; 
    setTimeout(function() { 
    callback({ 
     dummyDataPart: dummyData[token], 
     token: (typeof (dummyData[token]) == 'undefined') ? null : (token + 1) 
    }); 
    }); 
} 

// Here is how you would recursively call it with promises: 

function getAllData() { 
    //data accumulator is sitting within the function so it doesn't pollute the global namespace. 
    var dataSoFar = []; 

    function recursiveCall(token, resolve, reject) { 
    dummyAsyncCall(token, function(data) { 
     if (data.error) { 
     reject(data.error); 
     } 
     if (!data.token) { 
     //You don't need to return the resolve/reject result. 
     resolve(dataSoFar); 
     } else { 
     dataSoFar = dataSoFar.concat(data.dummyDataPart); 
     recursiveCall(data.token, resolve, reject); 
     } 
    }); 
    } 

    return new Promise(function(resolve, reject) { 
    // Note me passing resolve and reject into the recursive call. 
    // I like it this way but you can just store them within the closure for 
    // later use 
    recursiveCall(null, resolve, reject); 
    }); 
} 

//Here is the call to the recursive service. 
getAllData().then(function(data) { 
    console.log(data); 
}); 

Fiddle with me

+0

行 - 看起來很有希望 - 會試一試。 – CharlesA

+0

太好了 - 那是一種享受 - thx – CharlesA

1

這是因爲您不需要返回解析/拒絕,只需在遞歸調用完成時調用resolve/reject。一個粗略的代碼看起來像這樣

var getEndpoints = function(platformARN, token) { 

    return new models.sequelize.Promise(function(resolve, reject) { 
    var params = { 
     PlatformApplicationArn: platformARNDev 
    }; 
    if (token != null) { 
     params['NextToken'] = token; 
    } 
    sns.listEndpointsByPlatformApplication(params, function(err, data) { 
     if (err) { 
     reject(err); 
     } 
     else { 
     endpoints = endpoints.concat(data.Endpoints); //save to global var 
     if ('NextToken' in data) { 
      //call recursively 
      getEndpoints(platformARN, data.NextToken).then(function() { 
      resolve(true); 
      }).catch(function (err) { 
      reject(err); 
      }); 
     } 
     else { 
      console.log('trying to break out!'); 
      resolve(true);   
     } 
     } 
    }); 
    }); 
} 

注意:這只是一個粗略的代碼,可能工作也可能沒有,但就是給一個總體思路)

我添加了一個代碼下面的代碼段來支持這個概念,並且它很好用,請查看。

i = 0; 
 

 
$('#output').empty(); 
 

 
function pro() { 
 
    return new Promise(function(resolve, reject) { 
 
    if (i > 3) { 
 
     resolve(); 
 
     return; 
 
    } 
 
    window.setTimeout(function() { 
 
     console.log(i); 
 
     $('#output').append(i).append('<br/>'); 
 
     i += 1; 
 
     pro().then(function() { 
 
     resolve() 
 
     }).catch(function() { 
 
     reject() 
 
     }); 
 
    }, 2000); 
 
    }); 
 
} 
 

 
pro().then(function() { $('#output').append("now here"); })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> 
 

 
<div id="output"></div>

+0

嗨 - 我不認爲這是它。我以前沒有'return'的代碼。也剛剛重試 - 仍然是同樣的問題 – CharlesA

+0

謝謝。它實際上是服務器端節點代碼。 – CharlesA

+0

但JavaScript仍然是相同的語言,取代$('#輸出')。追加與console.log,它將是相同的 –