Большинство ответов здесь дают полезные советы, когда у вас есть одна операция async, но иногда это возникает, когда вам нужно выполнить асинхронную операцию для каждой записи в массиве или другом списке подобная структура. Искушение состоит в том, чтобы сделать это:
// WRONG
var results = [];
theArray.forEach(function(entry) {
doSomethingAsync(entry, function(result) {
results.push(result);
});
});
console.log(results); // E.g., using them, returning them, etc.
Пример:
// WRONG
var theArray = [1, 2, 3];
var results = [];
theArray.forEach(function(entry) {
doSomethingAsync(entry, function(result) {
results.push(result);
});
});
console.log("Results:", results); // E.g., using them, returning them, etc.
function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
max-height: 100% !important;
}
Причина, 't работа заключается в том, что обратные вызовы из doSomethingAsync
еще не запущены к тому моменту, когда вы пытаетесь использовать результаты.
Итак, если у вас есть массив (или список какого-то типа) и хотите выполнять асинхронные операции для каждой записи, у вас есть два варианта: выполнять операции параллельно (перекрывающиеся) или последовательно (последовательно последовательно).
Вы могут запускать все из них и отслеживать количество обратных вызовов, которые вы ожидаете, а затем использовать результаты, когда вы получили много обратных вызовов:
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
console.log("Results:", results); // E.g., using the results
}
});
});
Пример:
var theArray = [1, 2, 3];
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
console.log("Results:", results); // E.g., using the results
}
});
});
function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
max-height: 100% !important;
}
(Мы могли бы покончить с expecting
и просто использовать results.length === theArray.length
, но это оставляет нам открытым возможность того, что theArray
изменяется, пока вызовы выдающиеся ...)
Обратите внимание, как мы используем index
из forEach
, чтобы сохранить результат в results
в том же положении, что и запись это относится, даже если результаты a (поскольку асинхронные вызовы не обязательно завершаются в том порядке, в котором они были запущены).
Но что, если вам нужно вернуть те результаты от функции? Как указывали другие ответы, вы не можете; вы должны принять вашу функцию и вызвать обратный вызов (или вернуть Promise ). Вот вариант обратного вызова:
function doSomethingWith(theArray, callback) {
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
callback(results);
}
});
});
}
doSomethingWith(theArray, function(results) {
console.log("Results:", results);
});
Пример:
function doSomethingWith(theArray, callback) {
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
callback(results);
}
});
});
}
doSomethingWith([1, 2, 3], function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
max-height: 100% !important;
}
Или вот версия, возвращающая Promise
вместо:
function doSomethingWith(theArray) {
return new Promise(function(resolve) {
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
resolve(results);
}
});
});
});
}
doSomethingWith(theArray).then(function(results) {
console.log("Results:", results);
});
Конечно, если doSomethingAsync
передал нам ошибки, мы использовали бы reject
, чтобы отклонить обещание, когда мы получили сообщение об ошибке.)
Пример:
function doSomethingWith(theArray) {
return new Promise(function(resolve) {
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
resolve(results);
}
});
});
});
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
max-height: 100% !important;
}
(Или, альтернативно, вы можете сделать обертку для doSomethingAsync
, который возвращает обещание, а затем сделайте следующее ...)
Если doSomethingAsync
дает вам Promise , вы можете использовать Promise.all
:
function doSomethingWith(theArray) {
return Promise.all(theArray.map(function(entry) {
return doSomethingAsync(entry, function(result) {
results.push(result);
});
}));
}
doSomethingWith(theArray).then(function(results) {
console.log("Results:", results);
});
Пример:
function doSomethingWith(theArray) {
return Promise.all(theArray.map(function(entry) {
return doSomethingAsync(entry, function(result) {
results.push(result);
});
}));
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value) {
console.log("Starting async operation for " + value);
return new Promise(function(resolve) {
setTimeout(function() {
console.log("Completing async operation for " + value);
resolve(value * 2);
}, Math.floor(Math.random() * 200));
});
}
.as-console-wrapper {
max-height: 100% !important;
}
Обратите внимание, что Promise.all
решает свое обещание с помощью массива результатов всех обещаний, которые вы даете ему, когда все они разрешены, или отвергает его обещание, когда первый обещаний, которые вы ему даете, отклоняет.
Предположим, вы не хотите, чтобы операции были параллельны? Если вы хотите запускать их один за другим, вам нужно дождаться завершения каждой операции до начала следующего. Вот пример функции, которая делает это, и вызывает обратный вызов с результатом:
function doSomethingWith(theArray, callback) {
var results = [];
doOne(0);
function doOne(index) {
if (index < theArray.length) {
doSomethingAsync(theArray[index], function(result) {
results.push(result);
doOne(index + 1);
});
} else {
// Done!
callback(results);
}
}
}
doSomethingWith(theArray, function(results) {
console.log("Results:", results);
});
(Поскольку мы выполняем работу последовательно, мы можем просто использовать results.push(result)
, так как мы знаю, что мы не получим результаты не в порядке. В приведенном выше примере мы могли бы использовать results[index] = result;
, но в некоторых из следующих примеров у нас нет индекса для использования.)
Пример:
function doSomethingWith(theArray, callback) {
var results = [];
doOne(0);
function doOne(index) {
if (index < theArray.length) {
doSomethingAsync(theArray[index], function(result) {
results.push(result);
doOne(index + 1);
});
} else {
// Done!
callback(results);
}
}
}
doSomethingWith([1, 2, 3], function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
max-height: 100% !important;
}
(Или снова создайте обертку для doSomethingAsync
, которая дает вам обещание и выполните ниже ...)
Если doSomethingAsync
дает вам обещание, если вы можете использовать синтаксис ES2017 + (возможно, с транспилером, например Babel ), вы можете использовать функцию async
с помощью for-of
и await
:
async function doSomethingWith(theArray) {
const results = [];
for (const entry of theArray) {
results.push(await doSomethingAsync(entry));
}
return results;
}
doSomethingWith(theArray).then(results => {
console.log("Results:", results);
});
Пример:
async function doSomethingWith(theArray) {
const results = [];
for (const entry of theArray) {
results.push(await doSomethingAsync(entry));
}
return results;
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value) {
console.log("Starting async operation for " + value);
return new Promise(function(resolve) {
setTimeout(function() {
console.log("Completing async operation for " + value);
resolve(value * 2);
}, Math.floor(Math.random() * 200));
});
}
.as-console-wrapper {
max-height: 100% !important;
}
Если вы не можете использовать синтаксис ES2017 + (пока), вы можете использовать вариацию на Обещают уменьшить шаблон (это сложнее, чем обычное сокращение Promise, потому что мы не передаем результат от одного к другому, а вместо gat
function doSomethingWith(theArray) {
return theArray.reduce(function(p, entry) {
return p.then(function(results) {
return doSomethingAsync(entry).then(function(result) {
results.push(result);
return results;
});
});
}, Promise.resolve([]));
}
doSomethingWith(theArray).then(function(results) {
console.log("Results:", results);
});
Пример:
function doSomethingWith(theArray) {
return theArray.reduce(function(p, entry) {
return p.then(function(results) {
return doSomethingAsync(entry).then(function(result) {
results.push(result);
return results;
});
});
}, Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value) {
console.log("Starting async operation for " + value);
return new Promise(function(resolve) {
setTimeout(function() {
console.log("Completing async operation for " + value);
resolve(value * 2);
}, Math.floor(Math.random() * 200));
});
}
.as-console-wrapper {
max-height: 100% !important;
}
.. , который менее громоздк с функциями стрелок ES2015 + :
function doSomethingWith(theArray) {
return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
results.push(result);
return results;
})), Promise.resolve([]));
}
doSomethingWith(theArray).then(results => {
console.log("Results:", results);
});
Пример:
function doSomethingWith(theArray) {
return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
results.push(result);
return results;
})), Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value) {
console.log("Starting async operation for " + value);
return new Promise(function(resolve) {
setTimeout(function() {
console.log("Completing async operation for " + value);
resolve(value * 2);
}, Math.floor(Math.random() * 200));
});
}
.as-console-wrapper {
max-height: 100% !important;
}
, например:
// .vscode/settings.json in workspace
{
"files.associations": {
"*Container.js": "javascriptreact",
"**/components/*/*.js": "javascriptreact",
"**/config/routes.js": "javascriptreact"
}
}
Удерживайте Ctrl + Shift + P (или cmd на Mac), выберите «Change Language Mode» и там.
Но я все еще не могу найти способ сделать файлы, распознанные кодом VS с определенным расширением как некоторым определенным языком.
Это, например, приведет к тому, что файлы, заканчивающиеся на .variables
и .overrides
, будут обрабатываться так же, как и любой другой файл LESS. С точки зрения окраски кода, с точки зрения (авто) форматирования. Определите в пользовательских настройках или настройках проекта, как вам нравится.
(Семантический интерфейс использует эти странные расширения, если вам интересно)
TOOLS-> Опции-> Текстовый редактор-> Расширения файлов. Оттуда вы можете добавить расширение и выбрать известное расширение / язык, к которому вы хотите относиться.
Самый простой способ, который я нашел для глобальной ассоциации, - просто ctrl + km (или ctrl + shift + p и введите «change language mode») с файлом типа, который вы связываете с открытым.
В первом выборе будет «Настроить ассоциацию файлов для« x »(любой тип файла - см. прикрепленное изображение). Выбор этого делает постоянную ассоциацию filetype
Это может быть (возможно?) изменено с момента исходного вопроса / ответа, и я не знаю, когда), но это проще, чем ранее сделанные шаги редактирования вручную, и избегает необходимости обсуждать идентификаторы, которые могут быть не очевидны .
В Visual Studio Code вы можете добавить постоянные ассоциации файлов для выделения языка в ваш файл settings.json
следующим образом:
// Place your settings in this file to overwrite the default settings
{
"some_setting": custom_value,
...
"files.associations": {
"*.thor": "ruby",
"*.jsx": "javascript"
}
}
Вы можете открыть этот файл через меню: Файл> Настройки> Настройки. (Ctrl +, или Cmd +,)
Эта функция была впервые представлена в Visual Studio Code версии 1.0 (март 2016 г.). Проверьте доступные шаблоны шаблонов в примечаниях к выпуску и известных языковых строках в документации.
Привет, я придерживался другого подхода к решению практически той же проблемы, в моем случае я создал новое расширение, которое добавляет поддержку синтаксиса PHP для файлов Drupal, таких как .module и .inc): https://github.com/mastazi/VS-code-drupal
Как вы можете видеть в коде, я создал новое расширение, а не изменял существующее расширение PHP. Очевидно, что я объявляю зависимость от расширения PHP в расширении Drupal.
Преимущество этого в том, что если есть обновление для расширения PHP, моя пользовательская поддержка Drupal не теряется в процессе обновления.
Следуя шагам на , https://code.visualstudio.com/docs/customization/colorizer#_common-questions работал хорошо для меня:
Чтобы расширить существующий колоризатор, вы должны создать простой пакет.json в новой папке в .vscode / extensions и предоставить атрибут extensionDependencies, определяющий настройку, которую вы хотите добавить. В приведенном ниже примере добавляется расширение .mmd в раскрашиватель уценки. Обратите внимание, что не только имя extensionDependency соответствует настройке, но и идентификатор языка должен соответствовать идентификатору языка расширяемого вами колоризатора.
blockquote>{ "name": "MyMarkdown", "version": "0.0.1", "engines": { "vscode": "0.10.x" }, "publisher": "none", "extensionDependencies": [ "markdown" ], "contributes": { "languages": [{ "id": "markdown", "aliases": ["mmd"], "extensions": [".mmd"] }] } }
«cmd-k m» привязан к «workbench.action.editor.changeLanguageMode» по умолчанию, но я не нашел способ автоматически связать расширение файла с языковым режимом
Я нашел решение здесь: https://code.visualstudio.com/docs/customization/colorizer
Перейти к VS_CODE_FOLDER / resources / app / extensions / и там обновить package.json