비동기 기능 조합 + 대기 + setTimeout


305

새로운 비동기 기능을 사용하려고하는데 앞으로 문제를 해결하면 다른 사람들에게 도움이되기를 바랍니다. 이것은 작동하는 코드입니다.

  async function asyncGenerator() {
    // other code
    while (goOn) {
      // other code
      var fileList = await listFiles(nextPageToken);
      var parents = await requestParents(fileList);
      // other code
    }
    // other code
  }

  function listFiles(token) {
    return gapi.client.drive.files.list({
      'maxResults': sizeResults,
      'pageToken': token,
      'q': query
    });
  }

문제는 내 while 루프가 너무 빨리 실행되고 스크립트가 초당 너무 많은 요청을 Google API로 보냅니다. 따라서 요청을 지연시키는 절전 기능을 만들고 싶습니다. 따라서이 함수를 사용하여 다른 요청을 지연시킬 수도 있습니다. 요청을 지연시키는 다른 방법이 있으면 알려주십시오.

어쨌든, 이것은 작동하지 않는 새로운 코드입니다. 요청의 응답은 setTimeout 내에서 익명의 비동기 함수로 반환되지만 슬립 함수 resp에 응답을 반환하는 방법을 모르겠습니다. 초기 asyncGenerator 함수에.

  async function asyncGenerator() {
    // other code
    while (goOn) {
      // other code
      var fileList = await sleep(listFiles, nextPageToken);
      var parents = await requestParents(fileList);
      // other code
    }
    // other code
  }

  function listFiles(token) {
    return gapi.client.drive.files.list({
      'maxResults': sizeResults,
      'pageToken': token,
      'q': query
    });
  }

  async function sleep(fn, par) {
    return await setTimeout(async function() {
      await fn(par);
    }, 3000, fn, par);
  }

나는 이미 전역 변수에 응답을 저장하고 수면 함수, 익명 함수 내 콜백 등에서 응답을 저장하는 몇 가지 옵션을 시도했습니다.

답변:


614

당신의 sleep기능은 작동 setTimeout하지 않을 수있는 약속을 (아직?) 반환하지 않기 때문에 작동 하지 않습니다 await. 수동으로 약속해야합니다.

function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
async function sleep(fn, ...args) {
    await timeout(3000);
    return fn(...args);
}

Btw, 루프 속도를 늦추려면 sleep콜백을 가져 와서 이것을 연기 하는 함수 를 사용하고 싶지 않을 것입니다 . 차라리 같은 것을하는 것이 좋습니다

while (goOn) {
  // other code
  var [parents] = await Promise.all([
      listFiles(nextPageToken).then(requestParents),
      timeout(5000)
  ]);
  // other code
}

계산 parents에 최소 5 초가 걸립니다.


11
Promise.all접근 방식을 좋아하십시오 . 너무 간단하고 우아합니다!
Anshul Koka

4
의 표기법은 무엇을 var [parents]나타 냅니까? 나는 전에 그것을 보지
못했고

6
@NateUsher 그것은 배열 파괴입니다
Bergi

1
@tinkerr " timeout은 대기해야하는 경우 비동기로 선언해야합니다 . " -아니요. 함수는 기다릴 수있는 약속 만 반환하면됩니다 (또는 실제로는 다음으로 충분합니다). 그것이 그것을 구현하는 방법에 달려 있지만, 반드시 그럴 필요는 없습니다 async function.
Bergi

2
@naisanza 아니요, async/ await는 약속을 기반으로 합니다. 대체하는 것은 then전화입니다.
Bergi

150

Node 7.6부터는promisify utils 모듈 의 함수 기능을와 결합 할 수 있습니다 setTimeout().

Node.js

const sleep = require('util').promisify(setTimeout)

자바 스크립트

const sleep = m => new Promise(r => setTimeout(r, m))

용법

(async () => {
    console.time("Slept for")
    await sleep(3000)
    console.timeEnd("Slept for")
})()

1
nodeJS await require('util').promisify(setTimeout)(3000)는 다음과 같은 요구 없이도 달성 할 수 있습니다.await setTimeout[Object.getOwnPropertySymbols(setTimeout)[0]](3000)
Shl

5
재미있는 @Shl. 그래도 내 솔루션보다 읽기 쉽지 않다고 생각합니다. 사람들이 동의하지 않으면 솔루션에 추가 할 수 있습니까?
Harry

2
요구 버전은 버전보다 훨씬 낫습니다 getOwnPropertySymbols... 파산하지 않으면 ...!
Matt Fletcher

2
안녕하세요 @Harry. FlavorScape의 답변에서 하나의 라이너를 자신의 답변에 통합 한 것으로 보입니다. 나는 당신의 의도를 추측하고 싶지 않지만 실제로는 공평하지 않습니다. 수정 사항을 롤백 할 수 있습니까? 지금은 표절처럼 보입니다 ..
Félix Gagnon-Grenier

2
답변이 바로 아래에있는 것처럼 하나의 라이너를 제거했지만 대부분의 독자가 처음 몇 개의 응답을 지나치지 않기 때문에 많은 인기있는 답변이 다른 새로운 답변을 포함하도록 답변을 업데이트하는 것을 보았습니다.
Harry

130

빠른 한 줄짜리 인라인 방식

 await new Promise(resolve => setTimeout(resolve, 1000));

3
let sleep = ms => new Promise( r => setTimeout(r, ms));// 하나의 라이너 기능
Soldeplata Saketos

8
더 짧은 :-)await new Promise(resolve => setTimeout(resolve, 5000))
Liran Brimer

1
여러분이 같은 줄에서 "해결"x 2 번을 사용한다는 것은 무엇을 의미합니까? 처럼 : 새로운 약속을 기다립니다 (resolve => setTimeout (resolve, 1000)); ref. 그 자체로 또는 무엇으로? 대신 이와 같은 작업을 수행합니다. function myFunc () {}; 새로운 약속을 기다립니다 (resolve => setTimeout (myFunc, 1000));
PabloDK

35

setTimeoutasync기능 이 아니므 로 ES7 async-await와 함께 사용할 수 없습니다. 그러나 sleepES6 Promise를 사용 하여 함수를 구현할 수 있습니다 .

function sleep (fn, par) {
  return new Promise((resolve) => {
    // wait 3s before calling fn(par)
    setTimeout(() => resolve(fn(par)), 3000)
  })
}

그런 다음 sleepES7 async-await 에서이 새로운 기능 을 사용할 수 있습니다.

var fileList = await sleep(listFiles, nextPageToken)

, 참고하시기 바랍니다 난 단지 ES7 비동기 / await를 가진 결합에 대한 귀하의 질문에 대답 해요 있다는 setTimeout것이 도움이 초당 너무 많은 요청을 전송하여 문제를 해결할 수 있지만,.


업데이트 : 최신 node.js 버전에는 util.promisify 도우미 를 통해 액세스 할 수있는 buid-in 비동기 시간 초과 구현이 있습니다 .

const {promisify} = require('util');
const setTimeoutAsync = promisify(setTimeout);

2
fn던질 때 잡히지 않을 것입니다.
Bergi

@ Bergi 나는 그것이 new Promise당신이 할 수 있는 곳으로 버블 링 생각 sleep.catch합니다.
Florian Wendelborn

3
@Dodekeract 아니요, 비동기 setTimeout콜백 상태이며 new Promise콜백이 오랫동안 수행되었습니다. 전역 컨텍스트로 버블 링되어 처리되지 않은 예외로 처리됩니다.
Bergi

> 초당 너무 많은 요청을 보내는 데 문제가 있습니다. UI가 너무 많은 룰을 발생시키는 것을 막기 위해 "디 바운스"를 사용하려고합니다.
FlavorScape

5

같은 종류의 구문을 사용하려면 다음과 같은 setTimeout도우미 함수를 작성할 수 있습니다.

const setAsyncTimeout = (cb, timeout = 0) => new Promise(resolve => {
    setTimeout(() => {
        cb();
        resolve();
    }, timeout);
});

그런 다음 다음과 같이 호출 할 수 있습니다.

const doStuffAsync = async () => {
    await setAsyncTimeout(() => {
        // Do stuff
    }, 1000);

    await setAsyncTimeout(() => {
        // Do more stuff
    }, 500);

    await setAsyncTimeout(() => {
        // Do even more stuff
    }, 2000);
};

doStuffAsync();

나는 요지를 만들었다 : https://gist.github.com/DaveBitter/f44889a2a52ad16b6a5129c39444bb57


1
delayRun콜백 함수의 실행을 X 초 지연시키기 때문에 여기서 와 같은 함수 이름 이 더 의미가 있습니다. 기다리지 않는 예, IMO.
mix3d

2
var testAwait = function () {
    var promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('Inside test await');
        }, 1000);
    });
    return promise;
}

var asyncFunction = async function() {
    await testAwait().then((data) => {
        console.log(data);
    })
    return 'hello asyncFunction';
}

asyncFunction().then((data) => {
    console.log(data);
});

//Inside test await
//hello asyncFunction

0

다음 코드는 Chrome 및 Firefox 및 다른 브라우저에서 작동합니다.

function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
async function sleep(fn, ...args) {
    await timeout(3000);
    return fn(...args);
}

그러나 Internet Explorer에서에 대한 구문 오류가 발생합니다. "(resolve **=>** setTimeout..."


0

Dave답변 에서 영감을 얻은 유틸리티를 만들었습니다.

기본적으로 done작업이 끝나면 콜백을 콜백에 전달 합니다.

// Function to timeout if a request is taking too long
const setAsyncTimeout = (cb, timeout = 0) => new Promise((resolve, reject) => {
  cb(resolve);
  setTimeout(() => reject('Request is taking too long to response'), timeout);
});

이것이 내가 사용하는 방법입니다.

try {
  await setAsyncTimeout(async done => {
    const requestOne = await someService.post(configs);
    const requestTwo = await someService.get(configs);
    const requestThree = await someService.post(configs);
    done();
  }, 5000); // 5 seconds max for this set of operations
}
catch (err) {
  console.error('[Timeout] Unable to complete the operation.', err);
}

0

이것은 AWS Labdas에서 2020 년에 nodejs가있는 내 버전입니다.

const sleep = require('util').promisify(setTimeout)

async function f1 (some){
...
}

async function f2 (thing){
...
}

module.exports.someFunction = async event => {
    ...
    await f1(some)
    await sleep(5000)
    await f2(thing)
    ...
}

-3

이것은 하나의 라이너에서 더 빠른 수정입니다.

이것이 도움이되기를 바랍니다.

// WAIT FOR 200 MILISECONDS TO GET DATA //
await setTimeout(()=>{}, 200);

1
작동하지 않습니다. 이 : await setTimeout(()=>{console.log('first')}, 200); console.log ('second')인쇄 첫 번째
gregn3

1
요점은 @ gregn3입니다. 이것은 메인 프로그램 흐름 외부에서 "블로킹 작업"이 완료되는 동안 함수 외부의 코드가 계속 실행될 수있는 비 블로킹 솔루션입니다. 귀하와 Rommy 및 Mohamad이 제공 한 구문은 async 함수에서 대기 해야하는 요구 사항으로 인해 엄격하게 정확하지는 않지만 (최근 추가 사항 일 수 있음) node.js를 사용하고 있습니다. 이것은 내 조정 된 솔루션입니다. var test = async () => { await setTimeout(()=>{console.log('first')}, 1000); console.log ('second') }유용성을 보여주기 위해 시간 제한을 연장했습니다.
azariah
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.