Async फ़ंक्शन + प्रतीक्षा + सेटटाइमआउट का संयोजन


305

मैं नई async सुविधाओं का उपयोग करने की कोशिश कर रहा हूं और मुझे उम्मीद है कि मेरी समस्या को हल करने से भविष्य में दूसरों की मदद मिलेगी। यह मेरा कोड है जो काम कर रहा है:

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

समस्या यह है, कि मेरी जबकि लूप बहुत तेजी से चलता है और स्क्रिप्ट प्रति सेकंड कई अनुरोध Google एपीआई को भेजती है। इसलिए मैं एक नींद समारोह का निर्माण करना चाहता हूं जो अनुरोध को विलंबित करता है। इस प्रकार मैं इस फ़ंक्शन का उपयोग अन्य अनुरोधों में देरी करने के लिए भी कर सकता हूं। यदि अनुरोध में देरी का कोई और तरीका है, तो कृपया मुझे बताएं।

वैसे भी, यह मेरा नया कोड है जो काम नहीं करता है। रिक्वेस्ट की रिस्पॉन्स सेटटाइमआउट के भीतर अननोन असिंच फंक्शन में वापस आ जाता है, लेकिन मुझे नहीं पता कि मैं स्लीप फंक्शन रिस्पॉन्स के लिए कैसे रिस्पॉन्स लौटा सकता हूं। प्रारंभिक 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दृष्टिकोण से प्यार करें । इतना सरल और सुरुचिपूर्ण!
अंशुल कोका

4
var [parents]प्रतिनिधित्व का अंकन क्या है ? मैंने इसे पहले नहीं देखा है और यह गूगल पर एक कठिन बात है
natedog

6
@NateUsher यह सरणी destructuring
Bergi

1
@tinkerr " टाइमआउट को async घोषित करने की आवश्यकता है यदि इसे प्रतीक्षा करने की आवश्यकता है " - नहींं। एक फ़ंक्शन को केवल एक वादा वापस करने की आवश्यकता होती है जिसे प्रतीक्षा की जा सकती है (या वास्तव में, एक उल्लेखनीय पर्याप्त है)। यह कैसे प्राप्त होता है जो फ़ंक्शन के कार्यान्वयन तक है, यह एक होने की आवश्यकता नहीं है async function
बेर्गी

2
@naisanza नहीं है, async/ awaitहै के आधार पर वादा करता है। केवल एक चीज की जगह यह thenकॉल है।
बेर्गी

150

नोड 7.6 के बाद से , आप promisifyयूटिलिटी मॉड्यूल से फंक्शन फ़ंक्शन को जोड़ सकते हैं 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
नोडजेएस में await require('util').promisify(setTimeout)(3000)भी आवश्यकता के बिना प्राप्त किया जा सकता है:await setTimeout[Object.getOwnPropertySymbols(setTimeout)[0]](3000)
श्ल

5
दिलचस्प @ शाल। मुझे लगता है कि यह मेरे समाधान से कम पठनीय है, हालांकि। अगर लोग असहमत हैं तो मैं इसे समाधान में जोड़ सकता हूं?
हैरी

2
आवश्यकता संस्करण स्पष्ट रूप से getOwnPropertySymbolsसंस्करण की तुलना में बहुत बेहतर है ... अगर यह टूट नहीं गया है ...!
मैट फ्लेचर

2
अरे वहाँ @ हैरी। ऐसा प्रतीत होता है कि आपने अपने स्वयं के उत्तर में फ्लेवरस्केप के उत्तर से एक लाइनर को शामिल किया है। मैं आपके इरादों को मानना ​​नहीं चाहता, लेकिन यह वास्तव में उनके लिए उचित नहीं है। क्या आप अपना संपादन रोलबैक कर सकते हैं? अभी यह साहित्यिक चोरी की तरह लग रहा है ..
Félix Gagnon-Grenier

2
मैंने एक-लाइनर को हटा दिया है क्योंकि उत्तर नीचे है, हालांकि मैंने कई लोकप्रिय उत्तरों को अपने जवाबों को अपडेट करने के लिए अन्य नए उत्तरों को शामिल करने के लिए देखा है क्योंकि अधिकांश पाठक पहले कुछ प्रतिक्रियाओं को देखकर परेशान नहीं होते हैं।
हैरी

129

क्विक वन-लाइनर, इनलाइन तरीका

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

3
let sleep = ms => new Promise( r => setTimeout(r, ms));// एक लाइनर फ़ंक्शन
सोल्पेप्लाटा साकेतोस

8
इससे भी छोटा :-)await new Promise(resolve => setTimeout(resolve, 5000))
लिरन ब्रिमर

1
इसका क्या मतलब है जब आप लोग एक ही पंक्ति में 2 बार "रिज़ॉल्यूशन" x का उपयोग करते हैं? जैसे: नया वादा (संकल्प => सेटटाइमआउट (संकल्प, 1000)) का इंतजार करें; यह रेफरी करता है। खुद को या क्या? मैं इसके बजाय ऐसा कुछ करूंगा: myFunc () {}; नया वादा (संकल्प => setTimeout (myFunc, 1000)) का इंतजार करें;
पाब्लो डीके

35

setTimeoutएक asyncफ़ंक्शन नहीं है, इसलिए आप इसे ES7 async-wait के साथ उपयोग नहीं कर सकते। लेकिन आप sleepES6 प्रॉमिस का उपयोग करके अपने कार्य को कार्यान्वित कर सकते हैं :

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

तब आप sleepES7 async-wait के साथ इस नए फ़ंक्शन का उपयोग कर पाएंगे :

var fileList = await sleep(listFiles, nextPageToken)

कृपया, ध्यान दें कि मैं केवल आपके प्रश्न का उत्तर ES7 async / इंतजार के संयोजन के साथ दे रहा हूं setTimeout, हालांकि यह आपकी समस्या को प्रति सेकंड बहुत अधिक अनुरोध भेजने के साथ हल करने में मदद नहीं कर सकता है।


अपडेट: आधुनिक नोड.जेएस संस्करणों में क्विड-इन- एस्सेंसे टाइमटाइम कार्यान्वयन है, जो कि use.promisify हेल्पर के माध्यम से सुलभ है :

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

2
आपको ऐसा नहीं करना चाहिए, जब fnफेंकता गलत पकड़ा नहीं जाएगा।
बरगी

@Bergi मुझे लगता है new Promiseकि आप sleep.catchयह कर सकते हैं जहां तक यह बुलबुले ।
फ्लोरियन वेंडेलबोर्न

3
@Dodekeract नहीं, यह एक अतुल्यकालिक setTimeoutकॉलबैक में है और new Promiseकॉलबैक लंबे समय के लिए किया गया है। यह वैश्विक संदर्भ में बबल होगा और इसे एक अपवाद के रूप में फेंक दिया जाएगा।
बरगी

> प्रति सेकंड बहुत अधिक अनुरोध भेजने के साथ समस्या। आप यूआई फायरिंग जैसी चीजों को रोकने के लिए "बहस" का उपयोग करना चाहते हैं।
फ्लेवर्सस्केप

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यहाँ अधिक समझ में आता है, क्योंकि यह एक्सबैक द्वारा कॉलबैक फ़ंक्शन को चलाने में देरी करेगा। नहीं एक बहुत ही प्रतीक्षित आंख उदाहरण, IMO।
मिक्स

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

निम्न कोड क्रोम और फ़ायरफ़ॉक्स और शायद अन्य ब्राउज़रों में काम करता है।

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

डेव के उत्तर से प्रेरित एक उपयोग किया

मूल रूप से 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

यह मेरा संस्करण 2020 में नोड्स के साथ एडब्ल्यूएस लैबदास में है

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 जो कि हाँ है। यह एक गैर-अवरोधक समाधान है जहां फ़ंक्शन के बाहर कोड निष्पादित करना जारी रख सकता है, जबकि मुख्य प्रोग्राम प्रवाह के बाहर "ब्लॉकिंग ऑपरेशन" पूरा हो जाता है। यद्यपि सिंटैक्स आप और रम्मी और मोहम्मद ने प्रदान किया है, लेकिन एक async फ़ंक्शन में रैप करने के लिए आवश्यकता के कारण कड़ाई से सही नहीं है (एक हाल ही में जोड़ा जा सकता है), मैं भी नोड का उपयोग कर रहा हूँ। यह मेरा सुव्यवस्थित समाधान है। var test = async () => { await setTimeout(()=>{console.log('first')}, 1000); console.log ('second') }मैंने इसकी उपयोगिता दिखाने के लिए टाइमआउट बढ़ाया है।
अजर्याह
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.