Typescript дождаться выполнения функции

How To Delay a Function in TypeScript

By Omari Thompson-Edwards Hey, I’m Omari! I’m a full-stack developer from the UK, with a passion for ReactJS. I’m an enthusiastic and hardworking junior developer, driven by a desire to learn and explore ideas. Published: 28 February 2023

When developing TypeScript applications, you may need to delay the execution of a function for a certain amount of time. Delaying function execution can be useful for a variety of reasons, such as waiting for an animation to complete or for an API request to finish. In this article, I’ll show you how to delay function execution in TypeScript, step-by-step. We also have an article covering how to implement this in React here.

setTimeout()

To delay a function in TypeScript, you can use setTimeout(), which accepts a callback function and a delay time in milliseconds, after which it will call your function. Here’s the signature for it:

const timeoutId = setTimeout(function callbackFunction() <>, delayMs)
console.log('Ill print first'); setTimeout(() => < console.log('Ill print third after a second'); >, 1000); console.log('Ill print second');

And cancelling a timeout is also very simple. You might use this in something like React, where you might need to cancel the process before it finishes executing:

const firstTimeout = setTimeout(() => < console.log('I hope no-one cancels this timeout!'); >, 1000); setTimeout(() => < console.log('Cancelling the first timeout'); clearTimeout(firstTimeout); >, 500);

Here the first function never gets ran, since the timeout gets cancelled before it ever gets to execute. You might notice some possibly unexpected behaviour here; the function gets ran after our delay, but nothing will wait for it. Code after the timeout won’t be delayed. In some situations, this might be fine, but if you are looking for that behaviour, there’s still a way to get around this.

Читайте также:  Css редактор моделей для

Promise

By wrapping a promise around setTimeout, we can await it, and thus delay all of the code until that timeout finishes. Here’s the promise-ified setTimeout():

function delay(ms: number) < return new Promise((resolve) =>setTimeout(resolve, ms)); >
 console.log('Ill run first'); await delay(1000); console.log('Ill run second');

With my implementation, there is no callback function, but we can easily create a version which still calls a callback function when the timer runs out:

function setTimeoutPromise(callback: () => void, ms: number) < return new Promise((resolve) =>setTimeout(resolve, ms)).then(callback); >
 console.log('Ill run first'); await setTimeoutPromise(() => console.log('Ill run second'), 1000); console.log('Ill run third');

Conclusion

So there you have it! Now you know how to delay function execution in TypeScript like a pro. By following the simple steps we’ve outlined, you can easily add delays to your functions and create more dynamic and interactive applications. Whether you’re waiting for an API request to complete or simply want to add a pause between animations, this technique will come in handy time and time again. If you liked this article, or if you’re having any troubles, feel free to leave a comment below!

👋 Hey, I’m Omari Thompson-Edwards

Hey, I’m Omari! I’m a full-stack developer from the UK, with a passion for ReactJS. I’m an enthusiastic and hardworking junior developer, driven by a desire to learn and explore ideas.

Источник

Async Await¶

В качестве мысленного эксперимента представьте себе: способ сказать среде выполнения JavaScript приостановить выполнение кода по ключевому слову await при использовании вместе с промисом и возобновить только единожды (и если) промис выполнен:

// Псевдокод. Мысленный эксперимент async function foo()  try  var val = await getMeAPromise(); console.log(val); > catch (err)  console.log('Error: ', err.message); > > 

Когда промис завершён, выполнение функции продолжается,

  • если он исполнен, то await вернет значение,
  • если он отклонен, синхронно будет выброшена ошибка, которую мы можем отловить.

Это неожиданно (и волшебным образом) делает асинхронное программирование таким же простым, как синхронное программирование. Для этого мысленного эксперимента необходимы три вещи:

  • Возможность приостановить выполнение функции.
  • Возможность поместить значение внутри функции.
  • Возможность бросить исключение внутри функции.

Это именно то, что генераторы позволили нам сделать! Мысленный эксперимент на самом деле реален, как и реализация async / await в TypeScript / JavaScript. Под капотом просто используются генераторы.

Сгенерированный JavaScript¶

Вам не обязательно это понимать, но это довольно просто, если вы почитаете о генераторах. Функцию foo можно просто обернуть следующим образом:

const foo = wrapToReturnPromise(function* ()  try  var val = yield getMeAPromise(); console.log(val); > catch (err)  console.log('Error: ', err.message); > >); 

где wrapToReturnPromise просто выполняет функцию генератора для получения generator и затем использует generator.next() , если значение является promise , то оно выполнит then + catch промиса и в зависимости от результата вызовет generator.next(result) или generator.throw(error) . Вот и всё!

Async Await поддержка в TypeScript¶

Async — Await поддерживается TypeScript, начиная с версии 1.7. Асинхронные функции начинаются с ключевого слова async; await приостанавливает выполнение, пока не будет получено значение из Promise.

Ранее async / await поддерживался только в es6, и транспилировался непосредственно в ES6 generators.

TypeScript 2.1 добавлена возможность выполнения в ES3 и ES5, что означает, что вы можете использовать async / await независимо от того, какую среду вы используете. Важно отметить, что мы можем использовать async / await с TypeScript 2.1, и многие браузеры их поддерживают, конечно, сперва добавив глобально полифилл для Promise.

Давайте посмотрим этот пример и код, чтобы выяснить, как работает TypeScript async / await нотация:

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
function delay( milliseconds: number, count: number ): Promisenumber>  return new Promisenumber>((resolve) =>  setTimeout(() =>  resolve(count); >, milliseconds); >); > // асинхронная функция всегда возвращает Promise async function dramaticWelcome(): Promisevoid>  console.log('Hello'); for (let i = 0; i  5; i++)  // await преобразует Promise в число const count: number = await delay(500, i); console.log(count); > console.log('World!'); > dramaticWelcome(); 

Транспиляция в ES6 (—target es6)

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator)  return new (P || (P = Promise))(function ( resolve, reject )  function fulfilled(value)  try  step(generator.next(value)); > catch (e)  reject(e); > > function rejected(value)  try  step(generator['throw'](value)); > catch (e)  reject(e); > > function step(result)  result.done ? resolve(result.value) : new P(function (resolve)  resolve(result.value); >).then(fulfilled, rejected); > step( (generator = generator.apply( thisArg, _arguments || [] )).next() ); >); >; function delay(milliseconds, count)  return new Promise((resolve) =>  setTimeout(() =>  resolve(count); >, milliseconds); >); > // асинхронная функция всегда возвращает Promise function dramaticWelcome()  return __awaiter(this, void 0, void 0, function* ()  console.log('Hello'); for (let i = 0; i  5; i++)  // await преобразует Promise в число const count = yield delay(500, i); console.log(count); > console.log('World!'); >); > dramaticWelcome(); 

Вы можете увидеть полный пример здесь.

Транспиляция в ES5 (—target es5)

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator)  return new (P || (P = Promise))(function ( resolve, reject )  function fulfilled(value)  try  step(generator.next(value)); > catch (e)  reject(e); > > function rejected(value)  try  step(generator['throw'](value)); > catch (e)  reject(e); > > function step(result)  result.done ? resolve(result.value) : new P(function (resolve)  resolve(result.value); >).then(fulfilled, rejected); > step( (generator = generator.apply( thisArg, _arguments || [] )).next() ); >); >; var __generator = (this && this.__generator) || function (thisArg, body)  var _ =  label: 0, sent: function ()  if (t[0] & 1) throw t[1]; return t[1]; >, trys: [], ops: [], >, f, y, t, g; return ( (g =  next: verb(0), throw: verb(1), return: verb(2), >), typeof Symbol === 'function' && (g[Symbol.iterator] = function ()  return this; >), g ); function verb(n)  return function (v)  return step([n, v]); >; > function step(op)  if (f) throw new TypeError( 'Генератор уже выполняется.' ); while (_) try  if ( ((f = 1), y && (t = y[ op[0] & 2 ? 'return' : op[0] ? 'throw' : 'next' ]) && !(t = t.call(y, op[1])).done) ) return t; if (((y = 0), t)) op = [0, t.value]; switch (op[0])  case 0: case 1: t = op; break; case 4: _.label++; return  value: op[1], done: false, >; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if ( !((t = _.trys), (t = t.length > 0 && t[t.length - 1])) && (op[0] === 6 || op[0] === 2) )  _ = 0; continue; > if ( op[0] === 3 && (!t || (op[1] > t[0] && op[1]  t[3])) )  _.label = op[1]; break; > if ( op[0] === 6 && _.label  t[1] )  _.label = t[1]; t = op; break; > if (t && _.label  t[2])  _.label = t[2]; _.ops.push(op); break; > if (t[2]) _.ops.pop(); _.trys.pop(); continue; > op = body.call(thisArg, _); > catch (e)  op = [6, e]; y = 0; > finally  f = t = 0; > if (op[0] & 5) throw op[1]; return  value: op[0] ? op[1] : void 0, done: true, >; > >; function delay(milliseconds, count)  return new Promise(function (resolve)  setTimeout(function ()  resolve(count); >, milliseconds); >); > // асинхронная функция всегда возвращает Promise function dramaticWelcome()  return __awaiter(this, void 0, void 0, function ()  var i, count; return __generator(this, function (_a)  switch (_a.label)  case 0: console.log('Hello'); i = 0; _a.label = 1; case 1: if (!(i  5)) return [3 /*break*/, 4]; return [4 /*yield*/, delay(500, i)]; case 2: count = _a.sent(); console.log(count); _a.label = 3; case 3: i++; return [3 /*break*/, 1]; case 4: console.log('World!'); return [2 /*return*/]; > >); >); > dramaticWelcome(); 

Вы можете увидеть полный пример здесь.

Для обоих сценариев применения нам необходимо убедиться, что наш исполняемый код имеет глобальный доступ к ECMAScript-совместимому Promise. Как вариант это может быть использование полифилла для Promise. Мы также должны убедиться, что TypeScript знает, что Promise поддерживается, установив для нашего флага lib что-то вроде «dom», «es2015» или «dom», «es2015.promise», «es5».

Мы можем увидеть, какие браузеры имеют поддержку Promise (нативную и заполифилленную) здесь.

Источник

Оцените статью