Это первый день моего участия в августовском испытании обновлений, подробности о мероприятии:Испытание августовского обновления
асинхронная функция
имея в виду
Стандарт ES2017 представил асинхронные функции, чтобы сделать асинхронные операции более удобными.
Что такое асинхронная функция? Одним словом, это синтаксический сахар для Генераторных функций.
В предыдущей статье была функция Generator, которая по очереди считывает два файла.
const fs = require('fs');
const readFile = function (fileName) {
return new Promise(function (resolve, reject) {
fs.readFile(fileName, function(error, data) {
if (error) return reject(error);
resolve(data);
});
});
};
const gen = function* () {
const f1 = yield readFile('/etc/fstab');
const f2 = yield readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
функция кода вышеgen
можно записать какasync
функционируют следующим образом.
const asyncReadFile = async function () {
const f1 = await readFile('/etc/fstab');
const f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
Сравнение показывает, что,async
Функция является звездочкой Генераторной функции (*
) заменяется наasync
,Будуyield
заменитьawait
, это все.
async
Улучшение функции Генератора отражено в следующих четырех пунктах.
(1) Встроенный привод.
Выполнение функции генератора должно зависеть от исполнителя, поэтомуco
модуль, покаasync
У функций есть свои исполнители. То есть,async
Выполнение функции точно такое же, как и у обычной функции, требуется только одна строка.
asyncReadFile();
Приведенный выше код вызываетasyncReadFile
функция, то она автоматически выполнится и выведет окончательный результат. Это совсем не похоже на Генераторную функцию, которую нужно вызыватьnext
метод или использованиеco
Модуль можно реально выполнить и получить окончательный результат.
(2) Лучшая семантика.
async
а такжеawait
, по сравнению со звездочками иyield
, семантика яснее.async
Указывает, что в функции есть асинхронная операция,await
Указывает, что следующее выражение должно ожидать результата.
(3) Более широкая применимость.
co
соглашения модулей,yield
За командами могут следовать только функции Thunk или объекты Promise, иasync
функциональныйawait
После команды это может быть объект Promise и значение примитивного типа (числовое, строковое и логическое, но в этом случае оно будет автоматически преобразовано в сразу разрешенный объект Promise).
(4) Возвращаемое значение — Обещание.
async
Возвращаемое значение функции — объект Promise, что гораздо удобнее, чем возвращаемое значение функции Generator — объект Iterator. ты можешь использовать этоthen
Метод определяет следующее действие.
Дальше,async
Функцию можно рассматривать как несколько асинхронных операций, заключенных в объект Promise иawait
команда является внутреннейthen
Синтаксический сахар для команд.
Основное использование
async
Функция возвращает объект Promise, который можно использовать сthen
метод для добавления функции обратного вызова. Когда функция выполняется, как только она встречаетawait
Сначала он вернется, дождется завершения асинхронной операции, а затем выполнит операторы за телом функции.
Ниже приведен пример.
async function getStockPriceByName(name) {
const symbol = await getStockSymbol(name);
const stockPrice = await getStockPrice(symbol);
return stockPrice;
}
getStockPriceByName('goog').then(function (result) {
console.log(result);
});
Приведенный выше код представляет собой функцию для получения котировок акций, предыдущая функцияasync
ключевое слово, указывающее, что внутри функции есть асинхронная операция. Когда функция вызывается, она немедленно возвращаетPromise
объект.
Вот еще один пример, который указывает, через сколько миллисекунд выводить значение.
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello world', 50);
Приведенный выше код указывает, что через 50 миллисекунд выводhello world
.
из-заasync
Функция возвращает объект Promise, который можно использовать какawait
Параметры команды. Таким образом, приведенный выше пример также можно записать в следующем виде.
async function timeout(ms) {
await new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello world', 50);
Асинхронные функции могут использоваться в различных формах.
// 函数声明
async function foo() {}
// 函数表达式
const foo = async function () {};
// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)
// Class 的方法
class Storage {
constructor() {
this.cachePromise = caches.open('avatars');
}
async getAvatar(name) {
const cache = await this.cachePromise;
return cache.match(`/avatars/${name}.jpg`);
}
}
const storage = new Storage();
storage.getAvatar('jake').then(…);
// 箭头函数
const foo = async () => {};
грамматика
async
Правила синтаксиса функций в целом относительно просты, но сложность заключается в механизме обработки ошибок.
Возвращает объект обещания
async
Функция возвращает объект Promise.
async
внутри функцииreturn
Значение, возвращаемое оператором, станетthen
Параметры функции обратного вызова метода.
async function f() {
return 'hello world';
}
f().then(v => console.log(v))
// "hello world"
В приведенном выше коде функцияf
внутреннийreturn
Значение, возвращаемое командой, будетthen
Получена функция обратного вызова метода.
async
Внутри функции возникает ошибка, из-за которой возвращаемый объект Promise становитсяreject
условие. Выброшенный объект ошибки будетcatch
Получена функция обратного вызова метода.
async function f() {
throw new Error('出错了');
}
f().then(
v => console.log('resolve', v),
e => console.log('reject', e)
)
//reject Error: 出错了
Изменения состояния объектов Promise
async
Объект Promise, возвращаемый функцией, должен ждать, пока все внутренниеawait
Изменение состояния не произойдет до тех пор, пока объект Promise, следующий за командой, не будет выполнен, если только он не встретитreturn
заявление или выдать ошибку. То есть толькоasync
Асинхронная операция внутри функции будет выполняться после выполненияthen
Функция обратного вызова, указанная методом.
Ниже приведен пример.
async function getTitle(url) {
let response = await fetch(url);
let html = await response.text();
return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log)
// "ECMAScript 2017 Language Specification"
В приведенном выше коде функцияgetTitle
Есть три внутренних операции: захватить веб-страницу, извлечь текст и сопоставить заголовок страницы. Только после того, как все три операции будут завершены, он будет выполненthen
в методеconsole.log
.
команда ожидания
При нормальных обстоятельствах,await
За командой следует объект Promise, который возвращает результат этого объекта. Если это не объект Promise, он напрямую возвращает соответствующее значение.
async function f() {
// 等同于
// return 123;
return await 123;
}
f().then(v => console.log(v))
// 123
В приведенном выше кодеawait
Аргументы команды являются числовыми значениями.123
, что эквивалентноreturn 123
.
В другом случаеawait
За командой следуетthenable
объект (то есть определяетthen
объект метода), затемawait
приравнивает его к объекту Promise.
class Sleep {
constructor(timeout) {
this.timeout = timeout;
}
then(resolve, reject) {
const startTime = Date.now();
setTimeout(
() => resolve(Date.now() - startTime),
this.timeout
);
}
}
(async () => {
const sleepTime = await new Sleep(1000);
console.log(sleepTime);
})();
// 1000
В приведенном выше кодеawait
За командой следуетSleep
экземпляр объекта. Этот экземпляр не является объектом Promise, но поскольку определениеthen
метод,await
относился бы к этому как кPromise
иметь дело с.
В этом примере также показано, как реализовать эффект сна. В JavaScript никогда не было синтаксиса для перехода в спящий режим, но с помощьюawait
Команда для приостановки работы программы на указанное время. упрощенныйsleep
выполнить.
function sleep(interval) {
return new Promise(resolve => {
setTimeout(resolve, interval);
})
}
// 用法
async function one2FiveInAsync() {
for(let i = 1; i <= 5; i++) {
console.log(i);
await sleep(1000);
}
}
one2FiveInAsync();
await
Если объект Promise после команды становитсяreject
статус, тоreject
параметры будутcatch
Функция обратного вызова метода получает его.
async function f() {
await Promise.reject('出错了');
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出错了
Обратите внимание, что в приведенном выше кодеawait
нет предшествующего утвержденияreturn
,ноreject
Параметры метода по-прежнему передаются вcatch
функция обратного вызова метода. здесь, если вawait
добавленныйreturn
, эффект тот же.
любойawait
Объект Promise после оператора становитсяreject
состояние, то весьasync
функция прервет выполнение.
async function f() {
await Promise.reject('出错了');
await Promise.resolve('hello world'); // 不会执行
}
В приведенном выше коде второйawait
оператор не выполняется, потому что первыйawait
Состояние оператора становитсяreject
.
Иногда мы хотим не прерывать последующие асинхронные операции, даже если предыдущая не удалась. В это время первыйawait
помещатьtry...catch
структуру, чтобы независимо от успеха асинхронной операции второйawait
будет казнен.
async function f() {
try {
await Promise.reject('出错了');
} catch(e) {
}
return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
// hello world
Другой способawait
За следующим объектом Promise следуетcatch
способ устранения ошибок, которые могут возникнуть ранее.
async function f() {
await Promise.reject('出错了')
.catch(e => console.log(e));
return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
// 出错了
// hello world
обработка ошибок
еслиawait
При последующей асинхронной операции возникает ошибка, тогда она эквивалентнаasync
Объект Promise, возвращаемый функцией,reject
.
async function f() {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出错了
В приведенном выше кодеasync
функцияf
После казни,await
Следующий объект Promise выдаст объект ошибки, в результате чегоcatch
Вызывается функция обратного вызова метода, и ее параметром является выброшенный объект ошибки. Конкретный механизм выполнения см. в разделе «Принцип реализации асинхронной функции» ниже.
Способ предотвращения ошибок также состоит в том, чтобы помещать их вtry...catch
в кодовом блоке.
async function f() {
try {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
} catch(e) {
}
return await('hello world');
}
Если есть несколькоawait
команда, может быть помещена в единыйtry...catch
в структуре.
async function main() {
try {
const val1 = await firstStep();
const val2 = await secondStep(val1);
const val3 = await thirdStep(val1, val2);
console.log('Final: ', val3);
}
catch (err) {
console.error(err);
}
}
В следующем примере используетсяtry...catch
структура для достижения нескольких повторных попыток.
const superagent = require('superagent');
const NUM_RETRIES = 3;
async function test() {
let i;
for (i = 0; i < NUM_RETRIES; ++i) {
try {
await superagent.get('http://google.com/this-throws-an-error');
break;
} catch(err) {}
}
console.log(i); // 3
}
test();
В приведенном выше коде, еслиawait
Если операция прошла успешно, она будет использованаbreak
оператор выходит из цикла; в случае неудачи он будетcatch
Захват оператора, а затем вход в следующий раунд цикла.
Примечания по использованию
Первый пункт, как уже упоминалось ранее,await
после командыPromise
объект, результат операции может бытьrejected
, так что лучше всегоawait
команда наtry...catch
в кодовом блоке.
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
// 另一种写法
async function myFunction() {
await somethingThatReturnsAPromise()
.catch(function (err) {
console.log(err);
});
}
Во-вторых, несколькоawait
Асинхронные операции, следующие за командой, если нет вторичной связи, лучше позволить им запускаться одновременно.
let foo = await getFoo();
let bar = await getBar();
В приведенном выше кодеgetFoo
а такжеgetBar
две независимые асинхронные операции (то есть независимые друг от друга), записанные как вторичная связь. Это занимает много времени, потому что толькоgetFoo
После завершения он будет выполненgetBar
, вы можете заставить их срабатывать одновременно.
// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
Вышеуказанные два способа написания,getFoo
а такжеgetBar
Все запускаются одновременно, что сокращает время выполнения программы.
Третий пункт,await
команду можно использовать только вasync
Среди функций, если они используются в обычных функциях, будет сообщено об ошибке.
async function dbFuc(db) {
let docs = [{}, {}, {}];
// 报错
docs.forEach(function (doc) {
await db.post(doc);
});
}
Приведенный выше код сообщит об ошибке, потому чтоawait
используется в обычных функциях. Однако, еслиforEach
Параметры метода изменены наasync
функции, есть и проблема.
function dbFuc(db) { //这里不需要 async
let docs = [{}, {}, {}];
// 可能得到错误结果
docs.forEach(async function (doc) {
await db.post(doc);
});
}
Приведенный выше код может работать некорректно, причина в том, что триdb.post()
Операции будут выполняться параллельно, то есть параллельно, а не последовательно. Правильное написание - использоватьfor
цикл.
async function dbFuc(db) {
let docs = [{}, {}, {}];
for (let doc of docs) {
await db.post(doc);
}
}
Другой способ — использовать массивreduce()
метод.
async function dbFuc(db) {
let docs = [{}, {}, {}];
await docs.reduce(async (_, doc) => {
await _;
await db.post(doc);
}, undefined);
}
В приведенном выше примереreduce()
Первый параметр методаasync
функция, которая вызывает первый параметр функции, чтобы быть объектом обещания, возвращаемой предыдущей операцией, поэтому вы должны использоватьawait
等待它操作结束。 Кроме того,reduce()
метод возвращаетdocs
последний элемент массиваasync
Результатом выполнения функции также является объект Promise, поэтому его тоже нужно добавить перед нимawait
.
надreduce()
В функции нет параметраreturn
заявление, причина в том, что основная цель этой функции состоит в том, чтобыdb.post()
Операция, а не возвращаемое значение. а такжеasync
функционировать с или безreturn
всегда возвращает объект Promise, поэтому здесьreturn
не нужно.
Если вы действительно хотите, чтобы несколько запросов выполнялись одновременно, вы можете использоватьPromise.all
метод. когда будет три запросаresolved
, следующие два способа написания имеют одинаковый эффект.
async function dbFuc(db) {
let docs = [{}, {}, {}];
let promises = docs.map((doc) => db.post(doc));
let results = await Promise.all(promises);
console.log(results);
}
// 或者使用下面的写法
async function dbFuc(db) {
let docs = [{}, {}, {}];
let promises = docs.map((doc) => db.post(doc));
let results = [];
for (let promise of promises) {
results.push(await promise);
}
console.log(results);
}
В-четвертых, асинхронные функции могут сохранять стек выполнения.
const a = () => {
b().then(() => c());
};
В приведенном выше коде функцияa
Асинхронная задача выполняется внутриb()
. когдаb()
При работе функцияa()
Не прерывает, а продолжает выполнение. Подожди покаb()
конец пробега, возможноa()
Давно пора,b()
Контекст, в котором это было, исчез. еслиb()
илиc()
ошибка, стек ошибок не будет включатьa()
.
Теперь измените этот пример наasync
функция.
const a = async () => {
await b();
c();
};
В приведенном выше кодеb()
Во время бегаa()
Есть приостановить выполнение, контекстная среда сохраняется. однаждыb()
илиc()
ошибка, стек ошибок будет включатьa()
.
Принцип реализации асинхронной функции
Принцип реализации асинхронной функции заключается в том, чтобы обернуть функцию-генератор и автоматический исполнитель в функцию.
async function fn(args) {
// ...
}
// 等同于
function fn(args) {
return spawn(function* () {
// ...
});
}
всеasync
Функции могут быть записаны во второй форме выше, гдеspawn
Функции являются автоматическими исполнителями.
нижеприведенныйspawn
Реализация функции в основном является копией предыдущего автоматического исполнителя.
function spawn(genF) {
return new Promise(function(resolve, reject) {
const gen = genF();
function step(nextF) {
let next;
try {
next = nextF();
} catch(e) {
return reject(e);
}
if(next.done) {
return resolve(next.value);
}
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}
Сравнение с другими методами асинхронной обработки
Мы используем пример, посмотрим на асинхронную функцию и сравнение промисов, функцию генератора.
Предполагая, что в элементе DOM развернута серия анимаций, предыдущая анимация может быть запущена только после окончания предыдущей анимации. Если в одной из анимаций есть ошибка, она не будет выполнена, а будет возвращено возвращаемое значение последней успешно выполненной анимации.
Во-первых, это способ написания Promise.
function chainAnimationsPromise(elem, animations) {
// 变量ret用来保存上一个动画的返回值
let ret = null;
// 新建一个空的Promise
let p = Promise.resolve();
// 使用then方法,添加所有动画
for(let anim of animations) {
p = p.then(function(val) {
ret = val;
return anim(elem);
});
}
// 返回一个部署了错误捕捉机制的Promise
return p.catch(function(e) {
/* 忽略错误,继续执行 */
}).then(function() {
return ret;
});
}
Хотя способ написания Promise значительно улучшен по сравнению с callback-функцией, но на первый взгляд код полностью соответствует API Promise (then
,catch
д.), семантику самой операции увидеть непросто.
Далее следует способ написания функции генератора.
function chainAnimationsGenerator(elem, animations) {
return spawn(function*() {
let ret = null;
try {
for(let anim of animations) {
ret = yield anim(elem);
}
} catch(e) {
/* 忽略错误,继续执行 */
}
return ret;
});
}
Приведенный выше код использует функцию Generator для обхода каждой анимации.Семантика понятнее, чем у Promise, и все пользовательские операции появляются вspawn
внутри функции. Проблема с таким способом написания заключается в том, что должен быть обработчик задач, который автоматически выполняет функцию Генератора.spawn
Функция является автоматическим исполнителем, она возвращает объект Promise и должна гарантироватьyield
Выражение, следующее за оператором, должно возвращать обещание.
Последний способ написать асинхронную функцию.
async function chainAnimationsAsync(elem, animations) {
let ret = null;
try {
for(let anim of animations) {
ret = await anim(elem);
}
} catch(e) {
/* 忽略错误,继续执行 */
}
return ret;
}
Видно, что реализация асинхронной функции самая лаконичная, самая семантически совместимая, и почти нет семантически нерелевантного кода. Он обеспечивает автоматический исполнитель в методе написания Генератора на уровне языка и не выставляет его пользователям, поэтому объем кода минимален. Если вы используете метод написания генератора, автоматический исполнитель должен быть предоставлен пользователем.
Пример: последовательное выполнение асинхронных операций
В реальной разработке часто встречается набор асинхронных операций, которые нужно выполнять последовательно. Например, удаленно прочитать набор URL-адресов по очереди, а затем вывести результаты в том порядке, в котором они были прочитаны.
Обещания пишутся следующим образом.
function logInOrder(urls) {
// 远程读取所有URL
const textPromises = urls.map(url => {
return fetch(url).then(response => response.text());
});
// 按次序输出
textPromises.reduce((chain, textPromise) => {
return chain.then(() => textPromise)
.then(text => console.log(text));
}, Promise.resolve());
}
Используйте приведенный выше кодfetch
метод удаленного чтения набора URL-адресов одновременно. каждыйfetch
Операции возвращают объект Promise, вставленныйtextPromises
множество. Потом,reduce
метод обрабатывает каждый объект Promise по очереди, а затем используетthen
, который объединяет все объекты Promise, поэтому результаты можно вывести последовательно.
Такой способ написания менее интуитивен и менее удобочитаем. Ниже приведена реализация асинхронной функции.
async function logInOrder(urls) {
for (const url of urls) {
const response = await fetch(url);
console.log(await response.text());
}
}
Код выше действительно сильно упрощен, проблема в том, что все удаленные операции второстепенны. Следующий URL-адрес будет прочитан только в том случае, если предыдущий URL-адрес возвращает результат, что неэффективно и является пустой тратой времени. Что нам нужно, так это делать удаленные запросы одновременно.
async function logInOrder(urls) {
// 并发读取远程URL
const textPromises = urls.map(async url => {
const response = await fetch(url);
return response.text();
});
// 按次序输出
for (const textPromise of textPromises) {
console.log(await textPromise);
}
}
В приведенном выше коде, хотяmap
Параметры методаasync
функция, но она выполняется одновременно, потому что толькоasync
Внутренняя часть функции является вторичным выполнением, а внешняя не затрагивается. Назадfor..of
используется внутри циклаawait
, тем самым достигая последовательного вывода.
ожидание верхнего уровня
Согласно спецификации синтаксиса,await
Команды могут появляться только внутри асинхронных функций, иначе будет сообщено об ошибке.
// 报错
const data = await fetch('https://api.example.com');
В приведенном выше кодеawait
Команда используется самостоятельно, если она не помещена в асинхронную функцию, будет сообщено об ошибке.
В настоящее время существуетПредложение по грамматике, позволяющее независимое использование на верхнем уровне модуляawait
команда, чтобы приведенная выше строка кода не сообщала об ошибке. Цель этого предложения - заимствованиеawait
Решить проблему асинхронной загрузки модулей.
// awaiting.js
let output;
async function main() {
const dynamic = await import(someMission);
const data = await fetch(url);
output = someProcess(dynamic.default, data);
}
main();
export { output };
В приведенном выше коде модульawaiting.js
выходное значениеoutput
, в зависимости от асинхронной операции. Мы оборачиваем асинхронную операцию в асинхронную функцию, а затем вызываем эту функцию, только после того, как асинхронная операция внутри будет выполнена, переменнаяoutput
будет иметь значение, иначе возвратundefined
.
Приведенный выше код также можно записать как непосредственную функцию.
// awaiting.js
let output;
(async function main() {
const dynamic = await import(someMission);
const data = await fetch(url);
output = someProcess(dynamic.default, data);
})();
export { output };
Ниже показано, как загрузить этот модуль.
// usage.js
import { output } from "./awaiting.js";
function outputPlusValue(value) { return output + value }
console.log(outputPlusValue(100));
setTimeout(() => console.log(outputPlusValue(100)), 1000);
В приведенном выше кодеoutputPlusValue()
Результат выполнения полностью зависит от времени выполнения. еслиawaiting.js
Асинхронная операция внутри не завершена, а загруженныйoutput
Значениеundefined
.
Текущее решение состоит в том, чтобы позволить исходному модулю выводить объект Promise и судить, завершилась ли асинхронная операция из этого объекта Promise.
// awaiting.js
let output;
export default (async function main() {
const dynamic = await import(someMission);
const data = await fetch(url);
output = someProcess(dynamic.default, data);
})();
export { output };
В приведенном выше кодеawaiting.js
кроме выводаoutput
, а также по умолчанию выводит объект Promise (после выполнения асинхронной функции сразу же возвращает объект Promise), по которому судят о завершении асинхронной операции.
Ниже приведен новый способ загрузки этого модуля.
// usage.js
import promise, { output } from "./awaiting.js";
function outputPlusValue(value) { return output + value }
promise.then(() => {
console.log(outputPlusValue(100));
setTimeout(() => console.log(outputPlusValue(100)), 1000);
});
В приведенном выше кодеawaiting.js
вывод объекта, помещенного вpromise.then()
Внутри это может гарантировать, что асинхронная операция будет завершена до чтенияoutput
.
Этот способ написания более сложен и эквивалентен требованию, чтобы пользователь модуля соблюдал дополнительный протокол использования и использовал модуль особым образом. Как только вы забудете загрузить промисы и просто используете метод обычной загрузки, код, который зависит от этого модуля, может дать сбой. Более того, если вышеуказанноеusage.js
Также есть внешний вывод, а это значит, что все модули в этой цепочке зависимостей должны быть загружены с помощью Promise.
высший уровеньawait
команда, чтобы решить эту проблему. Это гарантирует, что модуль не выведет значение, пока не завершится асинхронная операция.
// awaiting.js
const dynamic = import(someMission);
const data = fetch(url);
export const output = someProcess((await dynamic).default, await data);
В приведенном выше коде две асинхронные операции добавляются при выводеawait
Заказ. Этот модуль будет выводить значение только до завершения асинхронной операции.
Способ загрузки этого модуля следующий.
// usage.js
import { output } from "./awaiting.js";
function outputPlusValue(value) { return output + value }
console.log(outputPlusValue(100));
setTimeout(() => console.log(outputPlusValue(100)), 1000);
Приведенный выше код написан точно так же, как и обычная загрузка модуля. То есть пользователю модуля вообще все равно, все зависит от того, есть ли асинхронная операция внутри модуля, и может ли он загружаться нормально.
В это время загрузка модуля будет ожидать зависимого модуля (приведенный выше примерawaiting.js
) асинхронной операции завершается до выполнения кода позади, что-то вроде паузы. Таким образом, это всегда будет правильноoutput
Не одинаковое значение получается от разного времени загрузки тайминга.
Обратите внимание, что верхawait
Может использоваться только в модулях ES6, но не в модулях CommonJS. Это связано с тем, что модуль CommonJSrequire()
загружается синхронно, если есть верхний уровеньawait
, он не может обрабатывать загрузку.
Ниже находится верхний слойawait
несколько сценариев использования.
// import() 方法加载
const strings = await import(`/i18n/${navigator.language}`);
// 数据库操作
const connection = await dbConnector();
// 依赖回滚
let jQuery;
try {
jQuery = await import('https://cdn-a.com/jQuery');
} catch {
jQuery = await import('https://cdn-b.com/jQuery');
}
Обратите внимание, что если загрузка нескольких файлов включает верхний уровеньawait
Модуль команды, команда загрузки выполняется синхронно.
// x.js
console.log("X1");
await new Promise(r => setTimeout(r, 1000));
console.log("X2");
// y.js
console.log("Y");
// z.js
import "./x.js";
import "./y.js";
console.log("Z");
Приведенный выше код состоит из трех модулей, последнийz.js
нагрузкаx.js
а такжеy.js
, результат печатиX1
,Y
,X2
,Z
. это означает,z.js
не дождалсяx.js
Загрузка завершена, перейдите к загрузке еще разy.js
.
высший уровеньawait
Команда немного похожа на передачу права на выполнение кода другим модулям для загрузки, а после завершения асинхронной операции вернуть право на выполнение и продолжить выполнение вниз.