jQuery.когда () и затем () не работают с асинхронным событием

#javascript #jquery #deferred

#javascript #jquery #отложенный

Вопрос:

Я пытаюсь прочитать строки из текстового файла, выбрать одну строку из файла и вставить ее в div на html-странице.

 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 получал то же значение для глобальной переменной chosenWord? Я не понимаю, почему функции when() и then() не работают в моем коде.

Комментарии:

1. wordFromFile не возвращает обещание, фактически оно ничего не возвращает — $.when работает с обещаниями, не undefined

Ответ №1:

Вы должны вернуть обещание в 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. Это сводит на нет некоторые функции автоматического распространения ошибок и их обработки, которые promises предоставляет.

Тогда вам $.when() вообще не нужно использовать в, setRandomWord() потому что wordFromFile() уже возвращает обещание, и вам нужно передать ссылку на функцию .then() без скобок после appendWord:

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

Резюмируя:

  1. Возвращает обещание из wordFromFile()
  2. Используйте .then() обработчик внутри wordFromFile() , а не обратный вызов jQuery.
  3. Удалите $.when() around wordFromFile() , поскольку это не требуется.
  4. Удалите скобки после appendWord при передаче ссылки на функцию .then() . Способ, которым вы это делали, заключался в немедленном вызове appendWord вместо того, чтобы разрешать .then() обработчику вызывать его позже, когда обещание будет выполнено.
  5. Ваша логика случайных чисел была не совсем правильной, если только вы всегда не пытались избегать первого слова.

Имейте в виду, что обещания не обладают магической силой. Они не «знают», когда каким-то образом выполняется асинхронная операция внутри них. Они знают, когда выполняется асинхронная операция, только когда эта асинхронная операция вручную разрешает обещание. Итак, вы не можете просто поместить некоторую асинхронную операцию внутри a $.when() и ожидать $.when() , что она волшебным образом узнает, когда эта асинхронная операция будет выполнена (многие люди пытаются это сделать, так что, по-видимому, это то, чего ожидают люди, не знакомые с promises). Вместо этого вы передаете обещания в $.when() , и асинхронные операции должны разрешить эти обещания. В вашем случае у вас есть только одно обещание, поэтому в нем нет необходимости $.when() . Обычно это необходимо только тогда, когда у вас есть более одного обещания, которого вы хотите дождаться. Когда у вас есть только одно обещание, вы можете просто вызвать .then() его.

Другие моменты, на которые следует обратить внимание:

  1. Вы используете глобальную переменную chosenWord для обратной передачи результатов. В этом нет необходимости и обычно это считается антишаблоном.
  2. У вас нет никакой обработки ошибок при вызове ajax.

Этот код:

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

});
  

можно было бы упростить до этого:

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

Если в теге body есть 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, никакой глобальный не используется.

Комментарии:

1. @Prosper — Поскольку, похоже, вы здесь новичок, когда получите ответ на свой вопрос, вам следует выбрать наилучший ответ, щелкнув зеленую галочку рядом с этим ответом. Это указывает сообществу, что на ваш вопрос получен ответ, и это приносит вам несколько очков репутации за соблюдение надлежащей процедуры.