【问题标题】:Resolve entire chain in each promise in $q.all before resolving next one在解析下一个之前解析 $q.all 中每个 promise 中的整个链
【发布时间】:2016-09-06 03:54:45
【问题描述】:

我正在循环遍历一个数组,并且在每个循环中,我添加一个 promise 数组,然后将其传递给 $q.all。每个链包括一个confirm() 对话和一个modal。用户的事件顺序应该是确认() - 模式 - 确认() - 模式。相反,我得到了确认() - 确认() - 模态 - 模态。另外,我希望在最后一个模式关闭后执行一个函数 refreshSelection(),但它目前会在最后一个 confirm() 对话关闭后立即触发。

    var promiseArr = [];
    var selection = []; // [obj1, obj1, obj3...]

    for (var i = 0; i < selection.length; i++) {
        promiseArr.push(getData(i));
    }

    $q.all(promiseArr)
        .then(refreshSelection);

    function getData(i) {
        var opts = {}; // selection[i].id is param

        return $http(opts)
            .then(onGetSuccess(i));
    }

    function onGetSuccess(i) {
        return function(result) {
            var shouldOpenModal = confirm(selection[i].text);

            if (shouldOpenModal == true) {
                openModal();
            }
        }
    }

    function openModal() {
        var copyPunchesModal = $uibModal.open({
            // modal template options
            }
        });

        copyPunchesModal.result.then(otherFunc, function () {
            console.log("Modal closed");
        });
    }

    function refreshSelection() {
        selection = [];
    }

我也尝试了以下方法,但无济于事。

    //...
    function getData(i) {
        var opts = {}; // selection[i].id is param

        return $http(opts)
            .then(onGetSuccess(i))
            .then(openConfirm)
            .then(openModal);
    }

非常感谢您的帮助。

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    你想使用一个 $.when 函数,它接受多个 promise 作为参数,并在它们全部完成时执行一个函数。或者,如果您同意它们按顺序完成,您可以将它们全部连接在一起。

    https://api.jquery.com/jquery.when/

    【讨论】:

    • 这是有角度的,不是 jquery。
    【解决方案2】:

    Q.all 没有指定解决承诺的顺序。如果您希望按照数组的顺序完成 Promise,则需要链接 Promise,以便当前 Promise 在前一个 Promise 的 .then() 内执行。

    你可以用 reduce 干净地做到这一点。

    I've got an answer here for ES6 promises,这里适配为Q:

    deferred = $q.defer();
    deferred.resolve();
    return selection.reduce(
        (accumulator, current) => accumulator.then(()=>getData(current)), 
        deferred.promise
    );
    

    请注意,您还需要修改 getData 函数以对对象本身进行操作(例如,currentSelection.text 而不是 selection[i].text

    【讨论】:

    • 感谢您的回复。当reduce() 移动到数组中的第二个元素时,累加器为undefined。我删除了箭头功能,希望我没有翻译错误。一般来说,我对 Promise 也很陌生,所以不确定回调是否应该返回不同的东西。 jsfiddle.net/d0Lkp6q0
    • 这不仅仅是一个箭头函数,而是一个表达式体箭头函数。正如您所料,它们只有一个表达式,因此不需要花括号,但它们也 return 该表达式。让您的构造函数返回 accumulator.then。您在 reduce 中返回的值将被视为下一次执行的累积值,因此如果您不返回任何内容,则下一个值是未定义的。
    • 啊,感谢您了解这一点。所以现在看来​​reduce 现在正在遍历整个数组,但getData() 永远不会执行。何时/如何调用它?
    • @devthorne 你能用你当前的代码更新你的问题或发布另一个 jsfiddle/pastebin 吗?
    • jsfiddle.net/d0Lkp6q0/1 - getData 永远不会触发。另外,我假设refreshSelection() 应该链接到selection.reduce(...),因为它返回一个承诺? -- 我尝试将.then() 链接到它,但该函数也没有执行。再次感谢。
    【解决方案3】:

    我想做类似的事情来避免溢出我的程序正在控制的设备 - 基本上我需要等待异步事务完成,然后再开始下一个事务。我使用 Promise 来强制执行执行顺序,并阻止直到每个项目完成。

    // the async thing we want to do, wrapped in a promise
    //
    function sendMessage = (message) {
        var promise = new Promise (resolve, reject) {
            // send message via an async function that provides success & fail callbacks, e.g. AJAX
            // replace 'asyncFunction', it's just a placeholder in this example
            asyncFunction (message, 
                function (response) {   // success callback
                    if (/*response is to my liking*/) {
                        resolve ();
                    } else {
                        reject (new Error (/*why I didn't like the response*/));
                    }
                },
                function (error) {  // failure callback
                    reject (error);
                }
        };
        return promise;
    }
    
    // the array we want to process in order
    var myMessages = ['hello', 'world', 'how', 'are', 'you', 'today?'];
    
    // iterator, and recursive function to loop thru array
    var idx = 0;
    function next () {
        if (idx < myMessages.length) {
            sendMessage (myMessages[idx++]).then (
                next,   // maps to the 'resolve' call in sendMessage
                function (err) {    // maps to the 'reject' calls in sendMessage
                    throw err;  // clearly, there's an option to be smarter than this
                }
            )
        }
    }
    
    // start the recursion
    next ();
    

    【讨论】:

      猜你喜欢
      • 2019-07-05
      • 2019-02-15
      • 2012-10-29
      • 2016-04-14
      • 2015-09-11
      • 2019-08-18
      • 2020-08-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多