JavaScript:while循环中的异步方法

Ste*_*tep 9 javascript asynchronous while-loop

我正在处理一个项目,要求我在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);
Run Code Online (Sandbox Code Playgroud)

这不起作用.循环在"完成"的值更新之前结束.我已经完成了一些关于这个主题的阅读,看来我需要使用promises或回调,因为API调用是异步的,但是我无法理解如何将它们应用到我上面的代码中.

帮助将不胜感激!

tim*_*tim 11

sigmasoldier解决方案是正确的,只是想与 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();
Run Code Online (Sandbox Code Playgroud)


Sig*_*ier 10

编辑:见底部,有真正的答案。

我鼓励你使用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
});
Run Code Online (Sandbox Code Playgroud)

语法在 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
});
Run Code Online (Sandbox Code Playgroud)

您还可以让您的 api 调用返回承诺并将其直接推送到承诺数组。

如果您不想编辑api_call_method,您可以随时将您的代码包装在一个新的Promise 中,并在它完成时调用该方法 resolve。

编辑:我现在已经看到了你的代码的重点,抱歉。我刚刚意识到 Promise.all 不会解决问题。

您应该将您发布的内容(不包括 while 循环和控制值)放入一个函数中,并根据条件再次调用它。

然后,所有这些都可以包装在一个 Promise 中,以使外部代码知道这个异步执行。稍后我将在我的 PC 上发布一些示例代码。

所以很好的答案

您可以使用 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(...){}"
 */
Run Code Online (Sandbox Code Playgroud)

  • 如果你的目标是 es6 那么使用 async wait。这里等级太多了 (2认同)

Zam*_*lli 5

如果您不想使用递归,您可以将while循环更改为for of循环并使用生成器函数来维护完成状态。这是一个简单的示例,其中for of循环将等待 async 函数,直到我们进行了 5 次迭代,然后将 done 翻转为 true。当您的 webservice 调用已缓冲所有数据行时,您应该能够更新此概念以将 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!');
});
Run Code Online (Sandbox Code Playgroud)