JQuery.when()然后()不使用异步事件

时间:2016-10-24 23:54:51

标签: javascript jquery deferred

我正在尝试从文本文件中读取行,从文件中选择一行并将其插入到html页面上的div。

var chosenWord="original word";

function wordFromFile(fileName) {
    $.get(fileName, function(data) {
        var lines = data.split("\n");
        var lineCount = lines.length;
        var randomIndex = Math.floor(Math.random() * ((lineCount-1) + 1));
        var word = lines[randomIndex];
        window.chosenWord = word;
        console.log("wordFromFile: "+chosenWord);
    });
}

function setRandomWord() {
  $.when(wordFromFile("http://mypage.com/words.txt")).then(appendWord());
}

function appendWord() {
  console.log("appendWord: "+window.chosenWord);
  $('.word').text(window.chosenWord);
}

$(function() {
  if($('body').is('.playpage')) {
    setRandomWord();
  }

});


console shows:
appendWord: original word
wordFromFile: particle //when i refresh the page this word changes but appendWord is always "original word"

如何才能使函数wordFromFile(fileName)首先完成,而appendWord获取全局变量selectedWord的相同值?我不明白为什么当()和then()函数在我的代码中不起作用时。

1 个答案:

答案 0 :(得分:0)

您必须在wordFromFile()中退回承诺。

function wordFromFile(fileName) {
    return $.get(fileName).then(function(data) {
        var lines = data.split("\n");
        var lineCount = lines.length;
        var randomIndex = Math.floor(Math.random() * lineCount);
        var word = lines[randomIndex];
        window.chosenWord = word;
        console.log("wordFromFile: "+chosenWord);
        return chosenWord;
    });
}

并且,如果您希望最终的chosenWord值成为promise的已解析值,那么您应该从.then()处理程序返回它。另外,请注意我已将$.get()上的回调更改为.then()处理程序,以使事情更加一致。一般来说,一旦你使用了promises,你就想在一个操作中一致地使用它们,而不是在promises中混合使用老式的回调。这样做会破坏承诺提供的一些自动错误传播和错误处理功能。

然后,您根本不需要在$.when()中使用setRandomWord(),因为wordFromFile()已经返回了一个承诺,您需要将函数引用传递给.then() } appendWord之后没有parens:

function setRandomWord() {
  wordFromFile("http://mypage.com/words.txt").then(appendWord);
}

回顾一下:

  1. wordFromFile()
  2. 返回承诺
  3. .then()内使用wordFromFile()处理程序而不是jQuery回调。
  4. 删除$.when()周围wordFromFile(),因为它不是必需的。
  5. 在将函数引用传递给appendWord时删除.then()后的parens。您使用它的方式是立即调用appendWord,而不是允许.then()处理程序稍后在promise解析时调用它。
  6. 你的随机数逻辑并不完全正确,除非你总是试图避开第一个单词。
  7. 请记住,承诺没有神奇的力量。他们不知道"当它们内部的异步操作以某种方式完成时。只有在异步操作手动解析承诺时,它们才会知道异步操作何时完成。所以,你不能在$.when()中放置一些异步操作,并期望$.when()神奇地知道异步操作何时完成(很多人尝试这样做,显然这是人们的新事物)承诺似乎期待)。相反,您将承诺传递给$.when(),异步操作必须解决这些承诺。在您的情况下,您只有一个承诺,因此不需要$.when()。通常只有在您想要等待多个承诺时才需要它。如果您只有一个承诺,则可以在其上调用.then()

    其他注意事项:

    1. 您正在使用全局变量chosenWord来回复结果。这不是必要的,通常被认为是一种反模式。
    2. 您的ajax通话没有任何错误处理。
    3. 此代码:

      $(function() {
        if($('body').is('.playpage')) {
          setRandomWord();
        }
      
      });
      

      可以简化为:

      $(function() {
        $("body.playpage").each(setRandomWord);
      });
      

      如果正文标记上有playpage类,则会调用setRandomWord()。如果没有,它就不会打电话。

      您可以从代码中删除chosenWord全局:

      function wordFromFile(fileName) {
          return $.get(fileName).then(function(data) {
              var lines = data.split("\n");
              var randomIndex = Math.floor(Math.random() * lines.length);
              var word = lines[randomIndex];
              console.log("wordFromFile: "+word);
              return word;
          });
      }
      
      
      function setRandomWord() {
        return wordFromFile("http://mypage.com/words.txt")).then(appendWord);
      }
      
      function appendWord(word) {
        console.log("appendWord: "+word);
        $('.word').text(word);
      }
      
      $(function() {
        $("body.playpage").each(setRandomWord);
      });  
      

      此处所选单词是wordFromFile()返回的承诺的已解析值,因此它将被传递给该承诺的任何.then()处理程序。当您将appendWord作为.then()处理程序传递时,这意味着该单词将被传递给appendWord。并且,wala没有使用全局。