【问题标题】:JavaScript Promises - Waiting for resolution before moving onJavaScript Promises - 在继续之前等待解决
【发布时间】:2017-10-05 08:21:45
【问题描述】:

我有以下要求:

  1. 通过调用内部函数 (getLines()) 获取“行”列表。
  2. 选择第一行,执行操作
  3. 上一个动作完成后,选择下一行,做同样的动作
  4. 对所有行重复(3-20 行,具体取决于用户)

我有以下代码:

App.Lines = response.data;    
for (var _i = 0; _i < App.Lines.length; _i++) {
    var makeCallPromise = new Promise(
        function(resolve, reject) {
            Session.connection.ol.makeCall(App.Lines[_i], callBackFunction(response) {
                //this can take up to 30 seconds to respond...
                resolve(response.data);
            }, errorCallBackFunction(message) {
                reject(message.error);
            }, bareJid);
        }
    )
    makeCallPromise.then(function(fulfilled) {
        console.log("PROMISE WORKED!!!!!", fulfilled);
    })
    .catch(function(error) {
        console.log("PROMISE FAILED!!!!!", error);
    });
}

我希望循环在继续循环之前等待解决承诺,但事实并非如此。 我的问题是是否有可能在解决方案完成之前停止循环。 注意 - 我正在使用 bluebird JS 库进行承诺。 谢谢!

亲切的问候,

加里

【问题讨论】:

  • 我认为你必须以某种方式return 承诺。就像在这种情况下,fulfilled 是您在承诺中使用的关键短语。
  • 不是循环整个事情,而是循环 makeCallPromise 并将这些承诺推送到一个数组。然后使用 Promise.all(array) 并在 promise.all 之后添加 then() 调用。结果将是所有promsies 将在第一个then() 被调用之前解决,因此所有数据都可以再次循环。或者,根本不使用循环,而是在前者解决后进行下一个 makeCallPromise。
  • @Shilly 谢谢,我已经尝试在 marvel308 提供的答案中使用它,使用 Promise.each()。我的回应是关于我做了什么和发生了什么。
  • Promises 101 - Promise 不会使异步代码同步:p

标签: javascript for-loop promise bluebird


【解决方案1】:

我不了解 bluebird,但您可以执行类似的操作来创建某种 for 循环,等待每个 Promise 在下一次迭代之前结束。

这是一个通用的例子,它当然可以优化,这只是一个快速的尝试:

var i = 0;
var performAsyncOperation = function(operationNumber) {
    return new Promise(function(resolve, reject){
    console.log('Operation number', operationNumber);
    resolve();
  });
}

var chainAsyncOperations = function() {
    if(++i < 10) {
        return performAsyncOperation(i).then(chainAsyncOperations);
    }
};
performAsyncOperation(i).then(chainAsyncOperations);

希望这会对你有所帮助;)

【讨论】:

  • 没有第三方库的干净工作解决方案。这是最好的解决方案
【解决方案2】:

你可以使用bluebird提供的Promise.each(),它会串行遍历一个数组,等待它们解析后再移动到数组中的下一个元素

【讨论】:

  • 我已经尝试通过迭代承诺并创建它们的数组(而不是在迭代中解决它们)来使用。然后我调用了 'Promise.each(promiseArray, function(result){console.log(result)}.then(function(fulfilled){console.log("WORKED")}).catch(function(error){ console.log("ERROR")}));'。问题是这不起作用,它仍然尝试同时执行 Session.connection.ol.makeCall 而无需等待第一个解决。
  • 你用过蓝鸟吗?
  • 嗯,我已经通过将 bluebird 库包含在
  • 忽略最后一条评论,我正在使用 requirejs 正确加载它:requirejs(['bluebird'], function (Promise) {//application code here});。但这仍然不起作用,它无需等待即可调用两个 makeCall 函数。
【解决方案3】:

这个用例完美匹配 ES7 特性async await,如果你有可能使用 babeljs 转译你的代码,你可以像这样重构你的函数:

function createPromise(line) {
    return new Promise(
       function(resolve, reject) {
          Session.connection.ol.makeCall(line, callBackFunction(response) {
              //this can take up to 30 seconds to respond...
              resolve(response.data);
          }, errorCallBackFunction(message) {
              reject(message.error);
          }, bareJid);
       }
    );
}

App.Lines = response.data;

async function main() {
    for (var _i = 0; _i < App.Lines.length; _i++) {
        try {
           var result = await createPromise(App.Lines[_i]);
           console.log(result);
        } catch (err) {
           console.log(err);
        }
    }
}

main().then(function() {
    console.log('finished');
});

【讨论】:

    【解决方案4】:

    你应该使用Bluebird#each方法:

    .each(function(any item, int index, int length) iterator) -> Promise

    迭代一个数组,或者一个数组的promise,它包含promise(或promise和values的混合),给定的迭代器函数带有签名(value, index, length),其中value是a的解析值输入数组中的相应承诺。迭代是连续发生的。如果输入数组中的任何 Promise 被拒绝,则返回的 Promise 也会被拒绝。

    Promise.each(App.Lines, line => {
        return new Promise((resolve, reject) => {
            Session.connection.ol.makeCall(line, callBackFunction(response) {
                resolve(response.data);
            }, errorCallBackFunction(message) {
                reject(message.error);
            }, bareJid);
        })
        .then(fulfilled => console.log("PROMISE WORKED!!!!!", fulfilled))
        .catch(err => onsole.log("PROMISE FAILED!!!!!", err));
    });
    

    【讨论】:

    • 嗨,这不起作用,我不太明白它在做什么。在一个简单的 1 Line 值的情况下,看起来它在同一时刻发出了两次Session.connection.ol.makeCall,所以我们立即失败了。当我将此更新为 2 行时,它会立即发出 4 个 Session.connection.ol.makeCall,然后在响应返回后又发出 2 个。
    • 根据您问题中的代码,App.Lines 是一个行数组,在我的代码中,我使用Bluebird#each 方法迭代该数组并为每一行调用Session.connection.ol.makeCal。您确定App.Lines 在第一种情况下有一行(一个元素),在第二种情况下有两行?在Promise.each 之前添加console.log(App.Lines.length)
    猜你喜欢
    • 2018-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-28
    • 2014-07-12
    相关资源
    最近更新 更多