async函数+ await + setTimeout的组合

JSh*_*ami 219 javascript settimeout async-await ecmascript-2017

我正在尝试使用新的异步功能,我希望解决我的问题将来会帮助其他人.这是我正在运行的代码:

  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
    });
  }
Run Code Online (Sandbox Code Playgroud)

问题是,我的while循环运行得太快,并且脚本每秒向google API发送太多请求.因此,我想建立一个延迟请求的睡眠功能.因此我也可以使用此函数来延迟其他请求.如果有其他方式延迟请求,请告诉我.

无论如何,这是我的新代码不起作用.请求的响应返回到setTimeout中的匿名异步函数,但我只是不知道如何将响应返回给sleep函数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);
  }
Run Code Online (Sandbox Code Playgroud)

我已经尝试了一些选项:将响应存储在全局变量中并从sleep函数返回它,在匿名函数中回调等等.

Ber*_*rgi 478

你的sleep功能不起作用,因为setTimeout(还没?)返回可以await编辑的承诺.您需要手动宣传它:

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

顺便说一下,为了减慢你的循环,你可能不想使用一个sleep接受回调的函数并且像这样推迟它.我宁愿建议做类似的事情

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

这让计算parents至少需要5秒钟.

  • 喜欢'Promise.all`方法.如此简单优雅! (8认同)
  • @NateUsher这是[阵列解构](/sf/ask/279044391/) (5认同)
  • `var [parents]`的符号代表什么?我以前没见过它,谷歌很难 (4认同)
  • @tinkerr [“如果需要等待超时,则需要将超时声明为异步*”](https://stackoverflow.com/review/suggested-edits/18044022) - 不。一个函数只需要返回一个可以被等待的承诺(或者实际上,一个 thenable 就足够了)。它如何实现取决于函数的实现,它不需要是一个“异步函数”。 (2认同)
  • @naisanza不,`async` /`await`是基于*承诺的。它唯一替代的是“ then”调用。 (2认同)
  • @fotoflo https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise。它是由 Promise 构造函数提供给您的函数,可让您通过调用它来解析 Promise (2认同)

Har*_*rry 112

从Node 7.6开始,您可以将promisifyutils模块中的函数函数与setTimeout().

Node.js的

const sleep = require('util').promisify(setTimeout)
Run Code Online (Sandbox Code Playgroud)

使用Javascript

const sleep = m => new Promise(r => setTimeout(r, m))
Run Code Online (Sandbox Code Playgroud)

用法

(async () => {
    console.time("Slept for")
    await sleep(3000)
    console.timeEnd("Slept for")
})()
Run Code Online (Sandbox Code Playgroud)

  • 有趣的@Shl.我认为它的可读性低于我的解决方案.如果人们不同意我可以将其添加到解决方案中吗? (5认同)
  • 在 nodeJS 中`await require('util').promisify(setTimeout)(3000)` 也可以通过以下方式实现:`await setTimeout[Object.getOwnPropertySymbols(setTimeout)[0]](3000)` (2认同)
  • require版本显然比`getOwnPropertySymbols`版本好得多......如果它没有破坏......! (2认同)
  • 嘿,@哈利。看来您在自己的答案中包含了FlavorScape答案中的一个衬里。我不想假定你的意图,但这对他们来说并不公平。您可以回滚您的编辑吗?现在看来有点窃。 (2认同)
  • @FélixGagnon-Grenier 他为什么要回滚,让他保留他的抄袭行为。好的想法应该被复制。 (2认同)
  • 我删除了单行代码,因为答案就在下面,但是我看到许多受欢迎的答案都会更新他们的答案,以包括其他新答案,因为大多数读者都不会去理会前几个答案。 (2认同)

Fla*_*ape 73

快速的单线,内联方式

 await new Promise(resolve => setTimeout(resolve, 1000));
Run Code Online (Sandbox Code Playgroud)

  • @PabloDK您可以将上面的一行扩展到[这个(更详细)版本](https://gist.github.com/mrienstra/8aa4eeeeab2012d2aa8ffc7f5e45f280),这希望可以清楚地说明为什么“resolve”出现两次。如果仍然令人困惑,请查看 [Promise 的 MDN 文档](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)。 (14认同)
  • `let sleep = ms => new Promise( r => setTimeout(r, ms));` // 一个线性函数 (9认同)
  • @PabloDK它也可以这样表示:`await new Promise((resolve,reject) => setTimeout(resolve, 1000));`。因此,“resolve”和“reject”是创建 Promise 时公开的回调。您只需告诉“setTimeout”执行“resolve()”即可。 (7认同)
  • 甚至更短:-)```等待新的Promise(resolve => setTimeout(resolve,5000))``` (6认同)
  • 当你们在同一行中使用“resolve”x 2 次时,这意味着什么?例如:await new Promise(resolve => setTimeout(resolve, 1000)); 它有参考吗?对自己还是什么?我会做这样的事情: function myFunc(){}; 等待新的 Promise(resolve => setTimeout(myFunc, 1000)); (5认同)
  • 你值得获得诺贝尔奖 (2认同)

Leo*_*tny 29

setTimeout不是一个async函数,所以你不能在ES7 async-await中使用它.但您可以sleep使用ES6 Promise实现您的功能:

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

然后你就可以在sleepES7 async-await中使用这个新功能了:

var fileList = await sleep(listFiles, nextPageToken)
Run Code Online (Sandbox Code Playgroud)

请注意,我只是回答了关于将ES7 async/await与之结合使用的问题setTimeout,尽管它可能无法帮助您解决每秒发送过多请求的问题.

  • @Dodekeract不,它在一个异步的`setTimeout`回调中,并且`new Promise`回调已经完成了很长时间.它将冒泡到全局上下文并作为未处理的异常抛出. (3认同)
  • 你不应该这样做,当`fn`抛出errror时不会被抓住. (2认同)

t_d*_*m93 17

2021 年更新

await setTimeout终于到了 Node.js 16,不再需要使用util.promisify()

import { setTimeout } from 'timers/promises';

(async () => {
  const result = await setTimeout(2000, 'resolved')
  // Executed after 2 seconds
  console.log(result); // "resolved"
})()
Run Code Online (Sandbox Code Playgroud)

官方 Node.js 文档:Timers Promises API(已在 Node 中构建的库)


Eri*_*yan 16

我将这段代码片段留在这里,供那些想要通过以下方式获取 API 调用(例如获取客户端)的人使用setTimeout

const { data } = await new Promise(resolve => setTimeout(resolve, 250)).then(() => getClientsService())
setName(data.name || '')
setEmail(data.email || '')
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案。 (2认同)

小智 10

await new Promise(resolve => setTimeout(() => { resolve({ data: 'your return data'}) }, 1000))
Run Code Online (Sandbox Code Playgroud)


小智 9

如果您想使用与setTimeout您可以编写这样的辅助函数相同的语法:

const setAsyncTimeout = (cb, timeout = 0) => new Promise(resolve => {
    setTimeout(() => {
        cb();
        resolve();
    }, timeout);
});
Run Code Online (Sandbox Code Playgroud)

然后你可以这样称呼它:

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

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

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

doStuffAsync();
Run Code Online (Sandbox Code Playgroud)

我做了一个要点:https : //gist.github.com/DaveBitter/f44889a2a52ad16b6a5129c39444bb57


小智 8

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
Run Code Online (Sandbox Code Playgroud)


zwi*_*ion 5

这是我在 2020 年在 AWS Labdas 中使用 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)
    ...
}
Run Code Online (Sandbox Code Playgroud)