Загрузка текстового файла в строку, асинхронно, с чистым JavaScript - PullRequest
0 голосов
/ 29 апреля 2018

У меня проблемы с загрузкой текстового файла в строку во внешнем javascript-приложении без каких-либо внешних библиотек.

xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", filename, true)
xmlhttp.send()

xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4)
        myvariable = xmlhttp.responseText
}

Этот код загружает текстовый файл в переменную асинхронно, но эта переменная доступна только внутри блока onreadystatechange, когда ответ в конечном итоге возвращается. Любая попытка вывести эту переменную за пределы этой области приводит к выполнению кода перед возвратом ответа, и переменная всегда неопределена.

function getFile(filename, callback) {

    xmlhttp = new XMLHttpRequest();
    xmlhttp.open("GET", filename, true)
    xmlhttp.send()

    xmlhttp.onreadystatechange = function() {
         if (xmlhttp.readyState == 4)
            callback(xmlhttp.responseText)
    }
 }

function loadFile(filename) {
    var myString
    getFile(filename, function(reponseText){
        myString = responseText
    })
    return myString
}

Некоторые люди предложили эту модель в качестве решения проблемы. Однако это представляет точно ту же проблему, что фактически решает проблему в большинстве сценариев, где это предлагается,

async: false

Я стараюсь абстрагироваться от процесса загрузки файла, так как он будет происходить несколько раз в моем коде и, возможно, будет пересмотрен несколько раз Я хочу, чтобы загрузка всего файла была абстрагирована в одну функцию, которую я могу вызывать в любом месте моего кода, не беспокоясь о вложении моего кода в обратные вызовы алгоритмически неважных задач ввода-вывода. Я также стараюсь избегать использования только синхронного запроса. Но, прочитав другие решения, я не уверен, возможно ли это.

Я пытаюсь сделать это в чистом JavaScript без каких-либо внешних библиотек.

РЕДАКТИРОВАТЬ 1/5/18

Попытавшись реализовать это с помощью async / await и Promises, я остался в очень похожей ситуации.

function getFile(filename) {
    return new Promise(function(resolve, reject){   

        xmlhttp = new XMLHttpRequest()
        xmlhttp.open("GET", filename, true)
        xmlhttp.overrideMimeType("text/plain")
        xmlhttp.send()

        xmlhttp.onload = function() {
            if (xmlhttp.status == 200) {
                resolve(xmlhttp.responseText)
            }
            else {
                reject()
            }
        }
    })
}

async function loadFile(filename) {
    myfile = await getFile(filename)
    return myfile
}

Вызов функции loadFile () возвращает обещание, которое разрешается до значения myfile. Однако, чтобы получить это значение, нам нужно позвонить

loadFile().then(myfile => { /* Use my varible here */})

Это оставляет меня в точно такой же ситуации, когда остальная часть моего кода должна быть обернута в функции, созданные неважными вызовами ввода-вывода. Странная вещь в этом заключается в том, что внутри функции loadFile (), которая объявлена ​​как асинхронная, если я использую ключевое слово await, код ведет себя синхронно, то есть поведение, которое я пытаюсь получить в остальной части моего кода.

async function loadFile(filename) {
    myfile = await getFile(filename)
    /* myfile is set here, like in syncronous code*/
    return myfile
    /* This returns a promise, getting us back to square 1*/
}

Синтаксис async / await, по-видимому, не дает никаких преимуществ по сравнению с использованием прямого обещания, мне все равно пришлось вручную создавать обещание, и я, похоже, распаковываю и перепаковываю полученное значение прямо в другое обещание.

Я что-то здесь упускаю?

1 Ответ

0 голосов
/ 29 апреля 2018

Вы можете передать объект в функцию loadFile и захватить fileResponse, как показано ниже:

    var fileObject = {
      fileResp: ''
    }

    function loadFile(filename, fileObject) {
        getFile(filename, function(reponseText){
            fileObject.fileResp = responseText
            triggerFileComplete()
        })
        return fileObject;
    }

   function triggerFileComplete() {
    // Do your next operation
    }

Возможно, позже или внутри triggerFileComplete вы можете использовать файлObject.fileResp.

...