2015-10-22 18 views
51

Sto cercando di utilizzare le nuove funzionalità asincrone di ES7 e spero che risolvere il mio problema aiuterà gli altri in futuro. Questo è il mio codice che sta lavorando:Combinazione di funzione asincrona + attendi + 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 
    }); 
    } 

Il problema è che il mio ciclo while corre troppo veloce e lo script invia troppe richieste al secondo per l'API di Google. Pertanto vorrei creare una funzione sleep che ritardi la richiesta. Quindi potrei usare questa funzione anche per ritardare altre richieste. Se c'è un altro modo per ritardare la richiesta, faccelo sapere.

In ogni caso, questo è il mio nuovo codice che non funziona. La risposta della richiesta viene restituita alla funzione async anonima all'interno del setTimeout, ma non so come posso restituire la risposta alla funzione sleep risp. alla funzione iniziale 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); 
    } 

ho già provato alcune opzioni: memorizzare la risposta in una variabile globale e restituirlo a partire dalla funzione sleep, richiamata all'interno della funzione anonima, ecc

risposta

150

La tua funzione sleep non funziona perché setTimeout non restituisce (ancora?) Una promessa che potrebbe essere await ed. Sarà necessario promisify manualmente:

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

Btw, a rallentare il ciclo che probabilmente non si vuole utilizzare una funzione sleep che prende un callback e rinvia in questo modo. Preferirei consiglio di fare qualcosa di simile

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

che permette il calcolo della parents prendere almeno 5 secondi.

+1

Adoro l'approccio 'Promise.all'. Così semplice ed elegante! –

+0

cosa rappresenta la notazione di 'var [genitori]'? Non l'ho visto prima ed è una cosa difficile da google – natedog

+1

@NateUsher È [array destructuring] (https: // stackoverflow.it/q/3986348/1048572) – Bergi

10

setTimeout non è una funzione async, in modo da non posso usarlo con ES7 async-await. Ma è possibile implementare la funzione sleep utilizzando ES6 Promise:

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

Allora sarete in grado di utilizzare questa nuova funzione sleep con ES7 async-attendono:

var fileList = await sleep(listFiles, nextPageToken) 

Si prega di notare che ho Sto solo rispondendo alla tua domanda sulla combinazione di ES7 async/attendi con setTimeout, anche se potrebbe non aiutarti a risolvere il tuo problema con l'invio di troppe richieste al secondo.

+2

Non si dovrebbe fare questo, quando 'fn' lancia il errror non verrebbe catturato. – Bergi

+0

@Bergi buon punto! –

+0

@Bergi Penso che salta alla 'nuova promessa' dove puoi' sleep.catch' it. – Dodekeract

0

È inoltre possibile utilizzare la funzione promisify dal modulo 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()