我正在处理一个项目,该项目要求我在API方法调用中使用JavaScript。我是一名Java程序员,之前从未进行过Web开发,所以我遇到了一些麻烦。
这个API方法是异步的,它在while循环中。如果它返回一个空数组,则while循环结束。否则,它循环。代码:
var done = true;
do
{
async_api_call(
"method.name",
{
// Do stuff.
},
function(result)
{
if(result.error())
{
console.error(result.error());
}
else
{
// Sets the boolean to true if the returned array is empty, or false otherwise.
done = (result.data().length === 0) ? true : false;
}
}
);
} while (!done);
这不起作用。循环在“完成”的值更新之前结束。我已经完成了一些关于这个主题的阅读,看来我需要使用promises或回调,因为API调用是异步的,但是我无法理解如何将它们应用到我上面的代码中。
帮助将不胜感激!
答案 0 :(得分:4)
我鼓励你使用Promise API。您可以使用Promise.all
电话解决问题:
let promises = [];
while(something){
promises.push(new Promise((r, j) => {
YourAsyncCall(() => r());
});
}
//Then this returns a promise that will resolve when ALL are so.
Promise.all(promises).then(() => {
//All operations done
});
语法在es6中,这里是es5等价物(Promise API可能包含在外部):
var promises = [];
while(something){
promises.push(new Promise(function(r, j){
YourAsyncCall(function(){ r(); });
});
}
//Then this returns a promise that will resolve when ALL are so.
Promise.all(promises).then(function(){
//All operations done
});
您也可以让api调用返回promise,并将其直接推送到promise数组。
如果您不想编辑 api_call_method ,您可以随时将代码包装在新的承诺中,并在完成后调用方法解析。
编辑:我已经看到了您的代码的重点,抱歉。我刚刚意识到Promise.all不会解决问题。
你应该把你发布的内容(不包括while循环和控制值)放在一个函数中,并根据调用它的条件。
然后,所有都可以包含在promise中,以使外部代码知道此异步执行。我稍后会用我的电脑发布一些示例代码。
您可以使用promise来控制应用程序的流程并使用递归而不是while循环:
function asyncOp(resolve, reject) {
//If you're using NodeJS you can use Es6 syntax:
async_api_call("method.name", {}, (result) => {
if(result.error()) {
console.error(result.error());
reject(result.error()); //You can reject the promise, this is optional.
} else {
//If your operation succeeds, resolve the promise and don't call again.
if (result.data().length === 0) {
asyncOp(resolve); //Try again
} else {
resolve(result); //Resolve the promise, pass the result.
}
}
});
}
new Promise((r, j) => {
asyncOp(r, j);
}).then((result) => {
//This will call if your algorithm succeeds!
});
/*
* Please note that "(...) => {}" equivals to "function(...){}"
*/
答案 1 :(得分:2)
如果您不想使用Promises
,可以重新构建代码:
var tasks = [];
var index = 0;
function processNextTask()
{
if(++index == tasks.length)
{
// no more tasks
return;
}
async_api_call(
"method.name",
{
// Do stuff.
},
function(result)
{
if(result.error())
{
console.error(result.error());
}
else
{
// process data
setTimeout(processNextTask);
}
}
);
}
答案 2 :(得分:1)
您也可以尝试递归解决方案。
function asyncCall(cb) {
// Some async operation
}
function responseHandler(result) {
if (result.error()) {
console.error(result.error());
} else if(result.data() && result.data().length) {
asyncCall(responseHandler);
}
}
asyncCall(responseHandler);
答案 3 :(得分:1)
sigmasoldier的solution是正确的,只是想与async / await共享ES6版本:
const asyncFunction = (t) => new Promise(resolve => setTimeout(resolve, t));
const getData = async (resolve, reject, count) => {
console.log('waiting');
await asyncFunction(3000);
console.log('finshed waiting');
count++;
if (count < 2) {
getData(resolve, reject, count);
} else {
return resolve();
}
}
const runScript = async () => {
await new Promise((r, j) => getData(r, j, 0));
console.log('finished');
};
runScript();
答案 4 :(得分:0)
您的循环无法正常工作,因为它是同步的,您的异步任务是异步的,因此循环将在异步任务甚至可以响应之前完成。我建议您使用Promises来管理异步任务:
if rank == 0:
df = pickle.load(open('lipad0406.p', 'rb'))
d = np.array(df, dtype=float)
m = d.size / size
comm.bcast(m)
else:
d = None
m = comm.bcast(None)
d_loc = np.zeros(m, dtype=float)
comm.Scatter(d,d_loc)
现在查看您的投票代码:
//first wrapping your API into a promise
var async_api_call_promise = function(methodName, someObject){
return new Promise((resolve, reject) => {
async_api_call(methodName, someObject, function(result){
if(result.error()){
reject( result.error() )
}else{
resolve( result.data() )
}
});
})
}
为什么要承诺?因为他们对异步操作进行状态管理。为什么要自己实现呢?
答案 5 :(得分:0)
如果不想使用递归,则可以将while
循环更改为for of
循环,并使用生成器函数来维护完成状态。这是一个简单的示例,其中for of
循环将等待异步函数,直到我们进行了5次迭代,然后将done翻转为true。当您的网络服务调用已缓冲所有数据行时,您应该能够更新此概念以将您的done变量设置为true。
let done = false;
let count = 0;
const whileGenerator = function* () {
while (!done) {
yield count;
}
};
const asyncFunction = async function(){
await new Promise(resolve => { setTimeout(resolve); });
};
const main = new Promise(async (resolve)=>{
for (let i of whileGenerator()){
console.log(i);
await asyncFunction();
count++;
if (count === 5){
done = true;
}
}
resolve();
});
main.then(()=>{
console.log('all done!');
});
答案 6 :(得分:0)
let taskPool = new Promise(function(resolve, reject) {
resolve("Success!");
});
let that = this;
while (index < this.totalPieces) {
end = start + thisPartSize;
if (end > filesize) {
end = filesize;
thisPartSize = filesize - start;
}
taskPool.then(() => {
that.worker(start, end, index, thisPartSize);
});
index++;
start = end;
}
答案 7 :(得分:0)
这是我想出的解决方案。将其放在异步函数中。
let finished = false;
const loop = async () => {
return new Promise(async (resolve, reject) => {
const inner = async () => {
if (!finished) {
//insert loop code here
if (xxx is done) { //insert this in your loop code after task is complete
finshed = true;
resolve();
} else {
return inner();
}
}
}
await inner();
})
}
await loop();