2015-10-22 3 views
51

Я пытаюсь использовать новые функции async для ES7, и я надеюсь, что решение моей проблемы поможет другим в будущем. Это мой код, который работает:Комбинация функции async + wait + setTimeout

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 
    }); 
    } 

Проблема заключается в том, что мой в то время как цикл выполняется слишком быстро, и скрипт отправляет слишком много запросов в секунду к API Google. Поэтому я хотел бы построить функцию сна, которая задерживает запрос. Таким образом, я мог бы также использовать эту функцию для задержки других запросов. Если есть другой способ отсрочить запрос, пожалуйста, дайте мне знать.

В любом случае, это мой новый код, который не работает. Ответ запроса возвращается анонимной асинхронной функции в setTimeout, но я просто не знаю, как я могу вернуть ответ на функцию сна resp. к исходной функции асинхронного генератора.

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); 
    } 

Я уже пробовал несколько вариантов: хранение ответа в глобальной переменной и вернуть его из функции сна, обратный вызов в анонимной функции и т.д.

ответ

150

Ваш sleep функция не работает, потому что setTimeout не (еще?) Возвращает обещание, которое может быть await ed. Вам нужно будет promisify вручную:

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 секунд.

+1

Любите подход 'Promise.all'. Так просто и элегантно! –

+0

Что означает обозначение 'var [parents]'? Я не видел этого раньше, и это сложно для google – natedog

+1

@NateUsher Это [destructuring] массива (https: // stackoverflow.com/q/3986348/1048572) – Bergi

10

setTimeout не является async функция, так что вы не может использовать его с ожиданием async ES7. Но вы могли бы реализовать sleep функцию с помощью ES6 Promise:

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

Тогда вы будете иметь возможность использовать эту новую функцию sleep с ES7 асинхронным-ОЖИДАНИЕ:

var fileList = await sleep(listFiles, nextPageToken) 

Обратите внимание, что я 'm отвечает только на ваш вопрос о объединении ES7 async/await с setTimeout, хотя это может не помочь решить вашу проблему при отправке слишком большого количества запросов в секунду.

+2

Вы не должны этого делать, когда 'fn' бросает ошибку, не будет поймано. – Bergi

+0

@Bergi хороший пункт! –

+0

@ Bergi Я думаю, что это пузырится до 'нового обещания', где вы можете' sleep.catch' его. – Dodekeract

0

Вы также можете использовать функцию promisify из модуля utils.

const { promisify } = require('util') 
const sleep = promisify(setTimeout) 

async function main() { 
    console.log("Started") 
    console.time("timer") 
    await method() 
    console.timeEnd("timer") 
    console.log("Finished") 
} 


async function method() { 
    await sleep(3000) 
} 

main()