【问题标题】:How to sequence a series of dynamically generated asynch operations using promises?如何使用 Promise 对一系列动态生成的异步操作进行排序?
【发布时间】:2017-04-06 18:06:48
【问题描述】:

在下面的例子中,我模拟了一个用户可以触发一些动作的场景,每个动作都是一个异步操作(包装在一个 Promise 中),可以通过随机时间来解决。

动作列表也是动态的,用户在一段时间内只能触发一个或多个动作。

我需要:

  • 保持承诺解决顺序,考虑到事先不知道完整的操作列表。

我可以使用 ES6 和浏览器原生 Promises

要测试示例,请多次(以可变频率)单击按钮。

  (function (window) {
            document.addEventListener('DOMContentLoaded', e => {
                let logActionsElm = document.getElementById('logActions');
                let logOperationsElm = document.getElementById('logOperations');
                let logCounterElm = document.getElementById('logCounter');
                let btnActionElm = document.getElementById('btnAction');

                let actionCounter = 0;

                let operationDurations = [1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000];
                let getRandomNumber = (min, max) => Math.floor(Math.random() * (max - 0 + min)) + min;
                let getRandomOperationDuration = x => operationDurations[getRandomNumber(0, 8)];

                let promises = [];

                let createAction = (id, duration) => {

                    logActionsElm.innerHTML += `${id} action_start_duration: ${duration} --------- ${id}<br>`;

                    let promiseAction = new Promise((resolve, reject) => {
                        setTimeout(e => {
                            logActionsElm.innerHTML += `${id} action_end___duration: ${duration} --------- ${id}<br>`;
                        }, duration);
                    });
                };

                let createOperation = x => {
                    actionCounter++;
                    let duration = getRandomOperationDuration() / 10;
                    createAction(actionCounter, duration);
                    //logActionsElm.innerHTML += `action ${actionCounter} created will resolve after ${duration}<br>`;
                };

                btnActionElm.addEventListener('click', e => {
                    createOperation();
                });

                var counter = 0;
                setInterval(x => {
                    if (counter >= 20) {
                        return;
                    }
                    counter++;
                    logCounterElm.innerHTML += `${counter} second <br>`;
                }, 1000);
            });
        })(window);
        body {
            font-size: 1.5em;
            font-family: 'Courier New';
        }

        #logCounter {
            position: fixed;
            top: 0;
            right: 0;
            margin: 2em;
        }
    <button id="btnAction">Triger and action</button>
    <div id="logActions"></div>
    <div id="logOperations"></div>
    <div id="logCounter"></div>

【问题讨论】:

    标签: javascript ecmascript-6 promise es6-promise


    【解决方案1】:

    您可以将新的操作函数附加到单个 Promise 中,以确保在所有先前的操作都解决之前不会评估操作:

    let queue = Promise.resolve();
    let userActionIdCounter = 0;
    
    function queueAction(fn) {
      queue = queue.then(fn);
      return queue;
    }
    
    function userAction() {
      return new Promise((resolve) => {
        const seconds = Math.ceil(Math.random() * 5);
        const actionId = userActionIdCounter;
        userActionIdCounter += 1;
        console.log('User action', userActionIdCounter, 'started');
        setTimeout(() => {
          console.log('User action', userActionIdCounter, 'complete');
          resolve();
        }, seconds * 1000);
      });
    }
    
    document.getElementById('action').addEventListener('click', () => {
      queueAction(userAction);
    });
    &lt;button id='action'&gt;Trigger action&lt;/button&gt;

    【讨论】:

    • 这个。这太微不足道了。否决这个的人不知道 Promise 是如何工作的。
    • @SimpleJ 确实是一个非常干净的解决方案。谢谢
    【解决方案2】:

    您不应创建自己的解决方案。相反,请从此处https://www.npmjs.com/search?q=promise+queue

    的大约 158 种现有解决方案中选择一种

    【讨论】:

    • 如果已经有 158 个解决方案,那么很有可能第 159 个解决方案不会更糟。你能推荐一个高质量的并展示如何使用它吗?
    • 我只是像其他人一样根据 npm 分数进行猜测。
    猜你喜欢
    • 2020-01-17
    • 2018-08-22
    • 2012-01-02
    • 2014-12-20
    • 2018-02-28
    • 2016-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多