在顺序循环中修改多个 Highcharts

Modify multiple Highcharts in a sequential loop

总结

我目前在一个给定页面上有大约 14 个股票图表的环境中工作(每个都有 20,0000 多个独特的数据点,还有更多)。我有某些全局 "toggles" 影响,例如,显示哪个系列、图表选项或轴极值(在所有图表上)。鉴于用户一次只能看到一个图表,我想像对待队列一样对待图表的更新,我先更新一个图表,然后更新另一个图表,依此类推。

我的目标:在循环中按顺序调用 Highcharts.Chart.redraw()(即,对页面中的每个图表调用重绘,一次调用一个 - 这样我的图表列表中的第一个图表首先被重绘).请注意,图表列表的排序是动态创建的并且已经处理好。

背景

到目前为止,我已经阅读了大量关于 JavaScript promises 的文章,我过去曾用它来链接 ajax 调用。如以下链接中所述:

我还在此处阅读了一些与循环中的 Promises 相关的更一般的问题:

代码/详细信息

我尝试了很多解决方案,并且相信问题围绕着制作 Highcharts 重绘函数 - 或者调用它的操作(如 Chart.update()、Series.setVisible()、Axis.setExtremes()) - return 一个承诺。

我上传了一个 shell here 的东西,它可以让你触发一个事件,并看到每个图表基本上是同时更新的。


例如,如下所示:

$(Highcharts.charts).each(function(i, chart) {
    console.log(i);
    // decide what to do with the chart
    // update Series, Chart options, Axis extremes... etc.
    chart.redraw(); // call redraw at the end
})

会输出:

> 1, 2, 3, ..., n // pause, then charts would redraw()

可能很重要的一点是,虽然上面的内容看起来是响应式的,但在我的环境中,单击切换和图表的重绘事件完成之间可能有 2-5 秒的延迟。

我想不通的是如何让循环等待每个图表完成重绘,然后再继续处理列表中的下一个图表。

如能提供任何帮助,我们将不胜感激。

如果我明白你的意思,你可以通过将触发器中的代码包装在 setTimeout 中(超时值为 0),然后包装在新的 Promise 中来实现它

使用 async/await 就像

$('#trigger').click(async (e) => {
    for (let chart of Highcharts.charts) {
        await new Promise(resolve => setTimeout(() => {
            chart.series.forEach(series => series.setVisible(undefined, false));
            chart.redraw();
            resolve();
        }, 0));
    }
});

通用解决方案

一般来说,如果你想在一个循环中按顺序链接 promise,你可以使用以下格式

function promiseChain(i) {
    return new Promise(resolve => {
        /* DO ASYNC STUFF */

        // Resolve with some result if the next item in the chain needs it
        return resolve("OK");
    });
}

let p = Promise.resolve(null);

for (let i = 0; i < 5; i++) {
    p = p.then(prevResult => {
        if (prevResult) {
            // Do stuff with prevResult if needed
        }

        // Chain next item
        return promiseChain(i);
    });
}

带日志的示例

这将记录数字 0-4,一次一个,在每个之间等待一秒钟。

function promiseChain(i) {
    return new Promise(resolve => {
        setTimeout(() => {
            console.log(i);
            return resolve("OK");
        }, 1000)
    });
}

let p = Promise.resolve(null);

for (let i = 0; i < 5; i++) {
    p = p.then(prevResult => {
        if (prevResult) {
            // Do stuff with prevResult if needed
        }

        return promiseChain(i);
    });
}