结合异步动作,promise.then()和递归setTimeout,同时避免“延迟反模式". [英] Incorporating async actions, promise.then() and recursive setTimeout whilst avoiding "deferred antipattern"

查看:89
本文介绍了结合异步动作,promise.then()和递归setTimeout,同时避免“延迟反模式".的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读实现轮询功能的方法,并在 https://davidwalsh上找到了一篇不错的文章.name/javascript-polling .现在,使用setTimeout而不是setInterval进行轮询可以使日志变得有意义,尤其是对于我无法控制并且已显示出不同的响应时间的API.

I have been reading up on methods to implement a polling function and found a great article on https://davidwalsh.name/javascript-polling. Now using a setTimeout rather than setInterval to poll makes a log of sense, especially with an API that I have no control over and has shown to have varying response times.

因此,我尝试在自己的代码中实现这样的解决方案,以挑战我对回调,promise和事件循环的理解.我遵循了该帖子中概述的指南,以避免使用任何反模式这是延迟反模式"吗? ?并确保在.then()在内部承诺解决了,这就是我陷入困境的地方.我已经将一些代码放在一起以模拟这种情况,因此我可以突出显示这些问题.

So I tried to implement such a solution in my own code in order to challenge my understanding of callbacks, promises and the event loop. I have followed guidance outlined in the post to avoid any anti-patterns Is this a "Deferred Antipattern"? and to ensure promise resolution before a .then() promise resolve before inner promise resolved and this is where I am getting stuck. I have put some code together to simulate the scenario so I can highlight the issues.

我的假设情况是这样的: 我有一个对使用userID响应的服务器的API调用.然后,我使用该用户ID向另一个数据库服务器发出请求,该服务器返回一组数据,该数据将执行一些可能花费几分钟的机器学习处理.

My hypothetical scenario is this: I have an API call to a server which responds with a userID. I then use that userID to make a request to another database server which returns a set of data that carries out some machine learning processing that can take several minutes.

由于延迟,任务被放入任务队列中,一旦完成,它将使用isComplete: falseisComplete: true更新NoSql数据库条目.这意味着我们随后需要每n秒对数据库进行一次轮询,直到获得指示isComplete: true的响应,然后我们才停止轮询.我了解轮询api有很多解决方案,但是我还没有看到涉及承诺,条件轮询以及不遵循先前链接文章中提到的一些反模式的解决方案.如果我错过了任何事情,而这是重复的话,我会提前致歉.

Due to the latency, the task is put onto a task queue and once it is complete it updates a NoSql database entry with from isComplete: false to isComplete: true. This means that we then need to poll the database every n seconds until we get a response indicating isComplete: true and then we cease the polling. I understand there are a number of solutions to polling an api but I have yet to see one involving promises, conditional polling, and not following some of the anti-patterns mentioned in the previously linked post. If I have missed anything and this is a repeat I do apologize in advance.

到目前为止,该过程由以下代码概述:

So far the process is outlined by the code below:

let state = false;
const userIdApi = ()  => {
    return new Promise((res, rej) => {
  console.log("userIdApi");
  const userId = "uid123";
      setTimeout(()=> res(userId), 2000)
    })
}

const startProcessingTaskApi = userIdApi().then(result => {
    return new Promise((res, rej) => {
    console.log("startProcessingTaskApi");
        const msg = "Task submitted";
      setTimeout(()=> res(msg), 2000)
    })
})

const pollDatabase = (userId) => {
    return new Promise((res, rej) => {
  console.log("Polling databse with " + userId)
      setTimeout(()=> res(true), 2000)
    })
}


Promise.all([userIdApi(), startProcessingTaskApi])
    .then(([resultsuserIdApi, resultsStartProcessingTaskApi]) => {
      const id = setTimeout(function poll(resultsuserIdApi){
        console.log(resultsuserIdApi)
        return pollDatabase(resultsuserIdApi)
        .then(res=> {
            state = res
            if (state === true){
              clearTimeout(id);
              return;
              }
            setTimeout(poll, 2000, resultsuserIdApi);
            })
            },2000)
        })

我有一个与此代码有关的问题,因为它无法按照我的需要进行轮询:

I have a question that relates to this code as it is failing to carry out the polling as I need:

我在帖子userIdApi似乎执行了两次;在startProcessingTaskApi定义中使用它,然后在Promise.all行中使用它.

I saw in the accepted answer of the post How do I access previous promise results in a .then() chain? that one should "Break the chain" to avoid huge chains of .then() statements. I followed the guidance and it seemed to do the trick (before adding the polling), however, when I console logged out every line it seems that userIdApi is executed twice; once where it is used in the startProcessingTaskApi definition and then in the Promise.all line.

这是已知事件吗?发生这种情况很有意义,我只是想知道为什么发送两个请求以执行相同的Promise还是可以的,或者是否有办法阻止第一个请求的发生并将函数执行限制为Promise.all语句?

Is this a known occurrence? It makes sense why it happens I am just wondering why this is fine to send two requests to execute the same promise, or if there is a way to perhaps prevent the first request from happening and restrict the function execution to the Promise.all statement?

对于来自JavaScript的Java语言,我是一个相当陌生的人,因此,如果有人指出我可能会缺少一些知识,以便能够完成此看似简单的任务,那么我将不胜感激.

I am fairly new to Javascript having come from Python so any pointers on where I may be missing some knowledge to be able to get this seemingly simple task working would be greatly appreciated.

推荐答案

我认为您快到了,看来您只是在为JavaScript的异步特性而苦苦挣扎.肯定会使用诺言,理解如何将诺言链接在一起是实现用例的关键.

I think you're almost there, it seems you're just struggling with the asynchronous nature of javascript. Using promises is definitely the way to go here and understanding how to chain them together is key to implementing your use case.

我将从实现包装setTimeout的单一方法开始,以简化操作.

I would start by implementing a single method that wraps setTimeout to simplify things down.

function delay(millis) {
    return new Promise((resolve) => setTimeout(resolve, millis));
}

然后,您可以使用delay函数重新实现"API"方法.

Then you can re-implement the "API" methods using the delay function.

const userIdApi = () => {
    return delay(2000).then(() => "uid123");
};

// Make userId an argument to this method (like pollDatabase) so we don't need to get it twice.
const startProcessingTaskApi = (userId) => {
    return delay(2000).then(() => "Task submitted");
};

const pollDatabase = (userId) => {
    return delay(2000).then(() => true);
};

只要不满足您的条件,您只需在链中链接另一个promise,就可以继续轮询数据库.

You can continue polling the database by simply chaining another promise in the chain when your condition is not met.

function pollUntilComplete(userId) {
    return pollDatabase(userId).then((result) => {
        if (!result) {
            // Result is not ready yet, chain another database polling promise.
            return pollUntilComplete(userId);
        }
    });
}

然后,您可以将所有内容放在一起以实现用例.

Then you can put everything together to implement your use case.

userIdApi().then((userId) => {
    // Add task processing to the promise chain.
    return startProcessingTaskApi(userId).then(() => {
        // Add database polling to the promise chain.
        return pollUntilComplete(userId);
    });
}).then(() => {
    // Everything is done at this point.
    console.log('done');
}).catch((err) => {
    // An error occurred at some point in the promise chain.
    console.error(err);
});

这篇关于结合异步动作,promise.then()和递归setTimeout,同时避免“延迟反模式".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆