Как использовать обещание в цикле do-while, ожидающем обратного вызова - PullRequest
0 голосов
/ 06 мая 2019

У меня есть обратный вызов, который ожидает ответа от HTTP-запроса, который отвечает словом «готово», если файл успешно загружен, и я делаю один запрос через обратный вызов, чтобы каждый раз загружать один файл.

Что я хочу, так это то, что когда ответ «готов», я хочу загрузить несколько файлов с циклом do-while, и я думаю сделать это с обещаниями, но я действительно не знаю, как.

Мой код сейчас:

var self = this;

let i = 0;
let fileInput = fileCmp.get("v.files");

do {

  // my callback
  self.uploadHelper(component, event, fileInput[i]);
  console.log("Uploading: " + fileInput[i].name);
  i++;

} while (i < fileInput.length);

Я хочу перейти на i=1 (второй файл) только тогда, когда я получу ответ "сделано" или что-то еще от вызова.

Мой обратный вызов, который вызывается с uploadHelper():

uploadChunk: function (component, file, fileContents, fromPos, toPos, attachId) {

  console.log('uploadChunk');
  var action = component.get("c.saveTheChunk");
  var chunk = fileContents.substring(fromPos, toPos);

  action.setParams({
    parentId: component.get("v.recordId"),
    fileName: file.name,
    base64Data: encodeURIComponent(chunk),
    contentType: file.type,
    fileId: attachId
  });

  action.setCallback(this, function (a) {

    console.log('uploadChunk: Callback');
    attachId = a.getReturnValue();

    fromPos = toPos;
    toPos = Math.min(fileContents.length, fromPos + this.CHUNK_SIZE);

    if (fromPos < toPos) {
      this.uploadChunk(component, file, fileContents, fromPos, toPos, attachId);
    } else {
      console.log('uploadChunk: done');
      component.set("v.showLoadingSpinner", false);
      // enabling the next button
      component.set("v.nextDisabled", false);
      component.set("v.uploadDisabled", true);
      component.set("v.clearDisabled", true);
      component.set("v.showToast", true);
      component.set("v.toastType", 'success');
      component.set("v.fileName", '');
      component.set("v.toastMessage", 'Upload Successful.');
    }
  });

  $A.getCallback(function () {
    $A.enqueueAction(action);
  })();
}

Ответы [ 4 ]

0 голосов
/ 06 мая 2019

Поскольку ваш uploadChunk выполняет асинхронную задачу, было бы целесообразно, чтобы функция принимала обратный вызов, который вызывается после выполнения задачи (ваш код еще не содержит обратного вызова). Поскольку обратные вызовы трудно обрабатывать (особенно с помощью циклов), имеет смысл заключить обратный вызов в Promise (который разрешается при вызове обратного вызова):

  uploadChunk: function (component, file, fileContents, fromPos, toPos, attachId) {
    return new Promise(resolve => { // the promise gets returned immeadiately, the "resolve" callback can be called to resolve it
      // ....
      action.setCallback(this, function (a) {
        //...
        resolve();
      });
    });
  },

Ваш uploadHelper теперь может возвращать обещание, возвращаемое обратно в цикл:

  uploadHelper(component, event, file) {
    //...
    return this.uploadChunk(component, file, /*...*/);
  }

Теперь, когда у нас это есть, мы можем просто await обещать внутри async функции:

 (async () => { // arrow function to preserve "this"
    for(const file of files) { // Why do...while if you can use a for..of?
      await this.uploadChunk(component, event, file);
    }
  })();
0 голосов
/ 06 мая 2019

Эй, вы можете сделать это с помощью функции автоматического запуска:

            var self = this;
            let i = 0;
            let fileInput = fileCmp.get("v.files");
            do{
                // my callback
                (()=>{
                   self.uploadHelper(component, event, fileInput[i]);
                   console.log("Uploading: "+fileInput[i].name);
                   i++;
                })();
            }
            while(i< fileInput.length);
0 голосов
/ 06 мая 2019

Вы должны сделать свой метод uploadHelper не aync для достижения того, что вы хотите.Попробуйте использовать объекты async, await и Promise, чтобы создать обещание в вашей функции (вместо обратного вызова) и заставить его происходить синхронно.

Это может выглядеть примерно так:

// uploadHelper definiton, fit its to your code
const uploadHelper = (component, event, file) => {

    // Create the promise
    return new Promise(function(component, event, file) {
        // Do what you want to do
    })
}

// Use it
var self = this;
let i = 0;
let fileInput = fileCmp.get("v.files");
do{
    await self.uploadHelper(component, event, fileInput[i]).then(function() {
        console.log("Uploading: "+fileInput[i].name);
        i++;
    });
}
while(i< fileInput.length);

Для получения дополнительной информации пройдите по этим ссылкам: https://developer.mozilla.org/he/docs/Web/JavaScript/Reference/Global_Objects/Promise https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

0 голосов
/ 06 мая 2019

Избавьтесь от цикла while и просто pop элемент из вашего массива fileInput каждый раз, когда вы его используете.Отмените все, когда массив станет пустым.

(хотя вам нужна работающая функция обратного вызова ...)

...