简体   繁体   English

以正确的顺序执行承诺的循环

[英]Executing a For Loop of Promises in the Correct Order

I am writing a program which takes a sentence and replaces abbreviations with their full terms from a database (eg, "hi and gm" --> "hello and good morning" if abbreviations stored in database are, "hi" --> "hello" and "gm" --> "good morning"). 我正在编写一个程序,该程序使用一个句子,并用数据库中的全部术语替换缩写(例如,“ hi and gm”->“ hello and good morning”,如果存储在数据库中的缩写为“ hi”->“你好”和“ gm”->“早上好”)。 The original sentence was stored in $('#translation').text(), and should be replaced accordingly. 原始句子存储在$('#translation')。text()中,应相应替换。

So I found out how to make getFullSentence() wait until the for loop has completed the helper function, getFullWord(), for each word by using promises. 因此,我发现了如何通过使用promises来使forFull等待for循环完成每个单词的辅助功能getFullWord()之前的getFullSentence()。

The problem is that getFullWord() is not being executed in sequential order, eg if I log "i" I get 0, 3, 1, 2 instead of 0, 1, 2, 3. How can I fix this problem? 问题是getFullWord()不能按顺序执行,例如,如果我登录“ i”,则会得到0、3、1、2而不是0、1、2、3。如何解决此问题? Thank you in advance! 先感谢您!

function getFullSentence(uid, sentence) {
    var promises = [];

    var words = sentence.split(" ");
    $.each(words, function(i, word) {
        promises.push(getFullWord(uid, word, i));
    });

    $.when.apply(null, promises).done(function() { 
        play($('#translation').text());
    });
}

function getFullWord(uid, word, i) {
    var defer = $.Deferred();

    $.get("/checkAbbreviation/" + uid + "/" + word, function(data) {
        word = data.full;

        var currSentence = $('#translation').text() + " ";
        var newSentence = currSentence + word.toUpperCase();
        $('#translation').text(newSentence);    
    }).done(function() {
        defer.resolve();
    });

    return defer.promise();
}

There are a lot of things wrong here. 这里有很多错误。 First off, you don't need to run your operations in sequence (like you seem to think you do). 首先,您不需要按顺序运行操作(就像您似乎认为的那样)。 You can run them in parallel and let $.when() collect the results for you in order. 您可以并行运行它们,并让$.when()依次为您收集结果。 This just requires that you do all your processing at the end after you've collected all the results and $.when() will collect them in order for you. 这仅要求您在收集所有结果之后最后进行所有处理,并且$.when()将为您收集它们。

Second, you are using a deferred anti-pattern where you create a promise around something that already returns a promise. 其次,您使用的是递延反模式,您可以在已返回承诺的事物周围创建承诺。 You can directly return the promise from $.ajax() rather than creating a new one. 您可以直接从$.ajax()返回诺言,而不必创建一个新的诺言。

Some other improvements: 其他一些改进:

  • You can use .map() to replace .each() and .push() . 您可以使用.map()替换.each().push()
  • You can use .join() to join all your strings. 您可以使用.join()连接所有字符串。
  • If you return a value from the .then() handler on $.ajax() , it vastly simplifies processing the results in $.when() . 如果您从$.ajax()上的.then()处理程序返回一个值,它将极大地简化$.when()结果的处理。 In this case, you want to return data.full.toUpperCase() anyway. 在这种情况下,您无论如何都要返回data.full.toUpperCase()
  • Use only .then() , not .done() . 仅使用.then() ,而不使用.done()
  • With $.ajax() don't mix callbacks and promises. 使用$.ajax()不要混用回调和承诺。 Use one or the other (promises are likely best). 使用其中之一(可能是最好的承诺)。

Here's a way to run your operations in parallel and collect the results in order: 这是一种并行运行操作并按顺序收集结果的方法:

function getFullSentence(uid, sentence) {
    var promises = sentence.split(" ").map(function(word, i) {
        return getFullWord(uid, word, i);
    });

    $.when.apply($, promises).then(function() { 
        // get all results into an array
        var results = Array.prototype.slice.call(arguments);
        var text = results.join(" ");
        $('#translation').text(text);
        play(text);
    });
}

function getFullWord(uid, word, i) {
    return $.get("/checkAbbreviation/" + uid + "/" + word).then(function(data) {
        // make resolved value be data.full
        return data.full.toUpperCase();
    });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM