2014-01-15 4 views
8

У меня есть следующий код, который работает в цикле:Передача переменной в асинхронной функции (обещание) в JavaScript

var index = fileNames[x].lastIndexOf("/") + 1; 
var currentImageName = fileNames[x].substr(index); 

if (currentImageName.indexOf(".jpg") != -1) { 
reader.getFileAsBlob(fileNames[x]) 
    .done(function(blob) { 
     picturesFilePathArray.push({ 
      fileName: currentImageName, 
      fileURL: blobURL(blob) 
     }); 
     refreshKMZList(); 
    }); 
} 

Проблема, которую я имею, что я пытаюсь сохранить объект с 2 свойства в массив. Этот объект должен иметь идентификатор и результат. (fileName и fileURL соответственно). Но так как эта функция асинхронна (выполняется через обещание). К тому времени, когда заканчивается «getFileAsBlob», currentImageName уже обновлен, в конечном итоге заканчивается на многих моих объектах, имеющих один и тот же идентификатор (последний обрабатывается до его завершения).

Это может быть очень простая проблема, но я очень новичок в javascript и еще ничего не нашел об этом.

Я думал, что решение может передать переменную функции «done», но я думаю, что эта функция является той, которая возвращается методом и уже установлена. (Я не знаю, как он выглядит)

Edit:

код только внутри нормального цикла

for (x = 0; x<fileNames.length; x++) 
+0

Думаю, вам нужно использовать закрытие javascript. Можем ли мы иметь полный код цикла? – BiAiB

+0

Закрытие: http://stackoverflow.com/questions/111102/how-do-javascript-closures-work – MiniGod

+0

Возможный дубликат [Закрытие Javascript внутри петель - простой практический пример] (http://stackoverflow.com/questions/750486/javascript-clos-inside-loops-simple-practice-example) – Barmar

ответ

8

Так создать функцию таким образом, переменная не может быть изменена

function getFile (filmName, imageName) { 
    reader.getFileAsBlob(fileName) 
    .done(function(blob) { 
     picturesFilePathArray.push({ 
      fileName: imageName, 
      fileURL: blobURL(blob) 
     }); 
     refreshKMZList(); 
    }); 
} 

и называть его

if (currentImageName.indexOf(".jpg") != -1) { 
    getFile (fileNames[x], currentImageName); 
} 

или вы можете сделать что-то вроде

if (currentImageName.indexOf(".jpg") != -1) { 
    (function (fileName, imageName) { 
    reader.getFileAsBlob(fileName) 
     .done(function(blob) { 
      picturesFilePathArray.push({ 
       fileName: imageName, 
       fileURL: blobURL(blob) 
      }); 
      refreshKMZList(); 
     }); 
    })(fileNames[x], currentImageName); 
} 

MDN Closure

+0

это сработало отлично, спасибо – Pochi

4

Решение этой задачи всегда одинакова: Используйте замыкание.

Но поскольку вы используете библиотеку, основанную на обещаниях, у вас есть более приятный вариант. Используйте обещания. (Внутренне это основано на затворов, а также, конечно, это просто гораздо лучше абстракции..)

function getFileInfo(path) { 
    return reader.getFileAsBlob(path).done(function (blob) { 
     return { 
      fileName: path.split('/').pop(), 
      fileURL: blobURL(blob) 
     }); 
    }; 
} 

function isJpg(filename) { 
    return /\.jpg$/i.test(filename); 
} 

Теперь вы можете сделать это, где refreshKMZList() вызывается один раз для каждого файла:

fileNames.filter(isJpg).forEach(function (path) { 
    getFileInfo(path).then(function (fileInfo) { 
     picturesFilePathArray.push(fileInfo); 
     refreshKMZList(); 
    }) 
    .catch(function (error) { 
     // handle the error 
    }); 
}); 

или даже это, где refreshKMZList() вызывается только один раз в целом:

var fileInfos = fileNames.filter(isJpg).map(getFileInfo); 

Promise.all(fileInfos).then(function (arrayOfFileInfo) { 
    picturesFilePathArray.concat(arrayOfFileInfo); 
    refreshKMZList(); 
}) 
.catch(function (error) { 
    // handle the error 
}); 

Читайте на обещания, они достойны быть понимание.

+0

спасибо за ваш ответ, этот loos очень изящный. Я получил пару вопросов tho, это "/\.jpg$/i.test (filename) "для файла с завершением jpg, предположим, но как я могу найти объяснение этого типа синтаксиса? (в google, как он называется). Можно ли добавлять другие типы файлов? jpeg, png, gif? и во-вторых, для решения, в котором выполняется refreshKMZList() один раз, isnt .all IE specific? и я должен написать его вот так? Promise.all (FileNames.map ...? Спасибо! – Pochi

+0

О, по твоим вопросам я вижу, что ты * на самом деле * на начальном уровне. Перед вами очень много изучений.;) Странный синтаксис называется «регулярным выражением». Это может быть червей его В вашей ситуации лучше использовать тот же трюк, который я использовал, чтобы вытащить последний сегмент пути. И 'document.all()' специфичен для IE, 'Promise.all () '- это что-то совсем другое. (Опять же, на момент написания этих обещаний [поддерживаются только в Google Chrome] (http://caniuse.com/#feat=promises) .) – Tomalak

+0

ха-ха, да, я думаю, у меня есть длинный путь. Большое спасибо за вашу помощь! – Pochi

Смежные вопросы