【问题标题】:Promise in a loop! How to?承诺循环!如何?
【发布时间】:2018-10-13 20:42:23
【问题描述】:

我一直试图让这段代码工作一段时间,但我似乎无法得到它。它用于实时更新图,它为每个点接收一个 [x, y] 数组,因此是一个数组数组。

输入是来自服务器的JSON 列表,它更新相同的JSON 对象(因此它更改了一个JSON 并仅更新值):

[
  {
    "Value": 10,
    "Name": "Name of variable"
  }
]

我只需要提取值。

我试过这样:

var getValueData = async function() {
    var valueJSON = await Promise.resolve($.getJSON( "{% url 'get_value' %}" ));
    return valueJSON[0]['Value'];
};

var data = [];
var totalPoints = 100;
var updateInterval = 1000;
var now = new Date().getTime();

function getData() {
    data.shift();

    while (data.length < totalPoints) {
        var value = [now += updateInterval,
                    getValueData().then(function(result) {
                        result;
                    })
                   ];

        data.push(value);
    };
};

基本上,getData() 正在尝试从JSON 构建X = timestamp.now() 和Y = "Value" 的数组,然后将该数组推送到我的"overall" 数据数组中。

这样做会使value 成为[&lt;timestamp&gt;, Unresolved] 的数组。

这样做:

while (data.length < totalPoints) {
    getZScoreData().then(function (result) {
        var valueArray = [now += updateInterval, result];
        data.push(valueArray);
    });
};

使valueArray 成为实际的[&lt;timestamp&gt;, &lt;JSON "value"],如果我console.log(value),除了这种方式似乎永远挂起服务器并为选项卡消耗大量RAM,就好像我在做一个无限循环(数百对 Web 服务器的获取请求,即使最大长度应为 100)。不过,我不确定 Promise 内部发生了什么来获得这种行为。

这是示例中的代码:

while (data.length < totalPoints) {     
    var y = Math.random() * 100;
    var value = [now += updateInterval, y];

    data.push(value);
};

看起来很简单。它说 y(在var value = [now += updateInterval, y]; 中)使“y”从我的 API 中获取值。

我不知道如何实际实现这一点。

我正在关注this Flot example 中的示例,但我无法使其与来自 AJAX 或 Promise 的实际实时值一起工作(我什至尝试过 fetch)。

“实时更新表”的所有示例最终都只使用math.random(),这很容易引起误解,因为它只是在移动,但并不是真正的实时。

我相信我没有正确解决循环中的承诺,但由于缺乏经验,在这一点上我什至不确定出了什么问题。

我不确定我将在我的代码中的哪个位置Y = "live value",或者我是否必须在某个地方返回结果?我对 Promises 或 AJAX 不太熟悉。

【问题讨论】:

  • 您遇到了什么错误?请完成完整的调试
  • getValueData() 正在返回一个常量,所以我相信你不能这样做 getValueData().then()
  • @Frondor 没有错误,它只是没有显示任何内容,因为数组的“y”值只是一个 Promise(未解析)对象,因此图形库不知道要做什么做它。我根本没有得到图表(预期)。如果我尝试使用挂起服务器的方法,我没有得到任何响应,它只是不断向服务器发送 get 请求。
  • Promise 是功能性的,它们不能很好地与循环相处。 Promise 已经有一些工具,如 Promise.all()Promise.race()dynamic sequential execution of promises 来处理您对重复出现的异步案例的需求。如果您喜欢循环,那么您应该研究async-await 抽象。

标签: javascript arrays get promise flot


【解决方案1】:

你应该记住的一些事情

  • 您的 getValueData 没有到达 return 语句,因为它 到达Promise.resolve 后立即解决。 (在我的例子中, 现在getData 返回一个承诺)
  • 使用Promise.all 这样您就不用等待了 在执行下一个之前完成上一个......它 一旦团队中的每个承诺解决,或者其中一个解决,就会解决 失败(你必须.catch 那)。
  • 了解更多关于Promises的信息,一开始他们很害怕,但you'll end up loving em

试试这个代码,它可能不起作用,因为我没有完整的工作示例,但你可以绕过错误并让它工作。

var results = [],
    totalPoints = 100,
    pointsLeft = totalPoints, // since we are using Promise.all, now we have to track this instead of results.length
    updateInterval = 1000,
    promises = [],
    getValueData = async function(timestamp) {
        await $.getJSON('yourURL').done(function (data) {
           pointsLeft-- // promise fulfilled 
           Promise.resolve({ data, timestamp })
        }).fail(Promise.reject)
    };

function getData() {
    // results.shift(); why?

    while (pointsLeft) {
        // push the promise to the stack, collect them later
        promises.push(getValueData(Date.now()))
    };


    Promise.all(promises).then(function (responses) {
        responses.forEach(function (data, timestamp) {
            results.push([timestamp, data])
        })
    }).catch(console.warn)
};

【讨论】:

    【解决方案2】:

    您可以生成 Promise 数组,然后使用 Promise.all 等待解析。

    // Let's imitate some async operation
    // It is instead of your getValueData
    function twiceAsync(a) {
      // returns a promise resolving to twice argument
      return new Promise(function(ok) {
        setTimeout(function(){ok(2*a)}, 100);
      });
    }
    
    var pList = [];
    for (var i = 0; i < 100; ++i) {
      // collect promises returned by twiceAsync to an array
      pList.push(twiceAsync(i));
    }
    
    Promise.all(pList) // provide array of promises to Promise.all
      .then(function(results) { // receive resolved results, they should be even numbers from 0*2 to 99*2
        console.log(results);
      })

    【讨论】:

    • 我不确定如何使用您的代码 sn-p 来实现这一点。它确实在我的控制台上记录了一个最多 200 的偶数数组,但我真的不明白那里发生了什么足以改变它来为我工作。抱歉,如果这听起来很愚蠢,但我是新手。
    • 我添加了一些关于你正在发生的事情的评论
    【解决方案3】:

    循环中的 Promise 很少是一个好主意,您通常希望使用 Promise.all() 一次执行多个 Promise,并将它们的结果收集到一个数组中:

    function getData() {
        // Note: Why is this here?
        data.shift();
    
        var promises = [];
        while (data.length < totalPoints) {
            promises.push(getValueData());
        }
    
        Promise.all(promises).then(results => {
            for (let result of results) {
                var value = [
                    now += updateInterval,
                    result
                ];
                data.push(value);
            }
        });
    };
    

    MDN 有一些关于 Promises 的好资料:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

    附带说明一下,同时执行 100 个 AJAX 请求听起来相当费劲,即使使用 Promise.all() 也是如此。如果您对后端有任何影响,您应该尝试优化后端,或者查看Workers 以​​批量执行请求。

    【讨论】:

    • data.shift() 用于删除数组中的第一项,以便图表不会保留最旧的值。至少据我了解是这样。 Flot 示例的文档不是很丰富。您应该深入了解源头并弄清楚发生了什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-15
    • 2019-06-17
    • 2015-12-18
    • 2021-09-07
    • 2018-03-25
    • 2015-11-27
    • 1970-01-01
    相关资源
    最近更新 更多