वापसी के लिए कॉलबैक के लिए "इंतजार" कैसे करें?


100

नीचे दिए गए उदाहरण में एक साधारण कॉलबैक का उपयोग करते समय:

test() {
  api.on( 'someEvent', function( response ) {
    return response;
  });
}

Async / प्रतीक्षा का उपयोग करने के लिए फ़ंक्शन कैसे बदला जा सकता है? विशेष रूप से, 'someEvent' को एक बार और केवल एक बार कॉल करने की गारंटी दी जाती है, मैं चाहूंगा कि फ़ंक्शन परीक्षण एक async फ़ंक्शन हो, जो कॉलबैक निष्पादित होने तक वापस नहीं आता है जैसे:

async test() {
  return await api.on( 'someEvent' );
}

1
बस संदर्भ के लिए, ES7 / ES2016 विनिर्देश को अंतिम रूप दिया गया है और इसमें async / प्रतीक्षा शामिल नहीं है। फिलहाल यह सिर्फ एक स्टेज 3 का प्रस्ताव है
डेन प्रिंस

खैर यह आश्चर्य की बात है - बहुत उम्मीद है कि यह शामिल हो जाता है! @DanPrince
sean2078

जवाबों:


146

async/awaitजादू नहीं है। एक async फ़ंक्शन एक ऐसा फ़ंक्शन है जो आपके लिए वादों को खोल सकता है, इसलिए आपको api.on()काम करने के लिए एक वादा वापस करना होगा। कुछ इस तरह:

function apiOn(event) {
  return new Promise(resolve => {
    api.on(event, response => resolve(response));
  });
}

फिर

async function test() {
  return await apiOn( 'someEvent' ); // await is actually optional here
                                      // you'd return a Promise either way.
}

लेकिन यह एक झूठ भी है, क्योंकि async फ़ंक्शंस भी खुद को वादा करता है, इसलिए आप वास्तव में मूल्य से बाहर नहीं जा रहे हैं test(), बल्कि एक मूल्य के लिए एक वादा करते हैं, जिसे आप इस तरह उपयोग कर सकते हैं:

async function whatever() {
  // snip
  const response = await test();
  // use response here
  // snip
}

3
फ़ंक्शन के लिए एक छोटा संस्करण जो एक वादा लौटाता है: const apiOn = (event) => new Promise(resolve => api.on(event, resolve));
फेलिप पलेट्स

7

यह कष्टप्रद है कि एक सीधा समाधान नहीं है, और लपेटना return new Promise(...)भयंकर रूप से है, लेकिन मैंने एक ठीक काम के आसपास पाया है util.promisify(वास्तव में यह भी थोड़े ही रैपिंग करता है, बस अच्छा लग रहा है)।

function voidFunction(someArgs, callback) {
  api.onActionwhichTakesTime(someMoreArgs, (response_we_need) => {
    callback(null, response_we_need);
  });
}

उपरोक्त फ़ंक्शन अभी तक कुछ भी वापस नहीं करता है। हम इसे कर Promiseके responseपारित की वापसी कर सकते callbackहैं:

const util = require('util');

const asyncFunction = util.promisify(voidFunction);

अब हम वास्तव awaitमें कर सकते हैं callback

async function test() {
  return await asyncFunction(args);
}

उपयोग करते समय कुछ नियम util.promisify

  • callbackसमारोह के अंतिम तर्क होने वाला है कि होना चाहिएpromisify
  • माना-कॉलबैक फॉर्म में होना चाहिए (err, res) => {...}

मजेदार बात यह है कि हमें विशेष रूप से यह लिखने की आवश्यकता नहीं है कि callbackवास्तव में क्या है।


3

async / प्रतीक्षा जादू है। आप asPromiseइस तरह की परिस्थितियों को संभालने के लिए एक समारोह बना सकते हैं :

function asPromise(context, callbackFunction, ...args) {
    return new Promise((resolve, reject) => {
        args.push((err, data) => {
            if (err) {
                reject(err);
            } else {
                resolve(data);
            }
        });
        if (context) {
            callbackFunction.call(context, ...args);
        } else {
            callbackFunction(...args);
        }
    });
}

और जब चाहें तब इसका उपयोग करें:

async test() {
    return await this.asPromise(this, api.on, 'someEvent');
}

आर्ग की संख्या परिवर्तनशील है।


1

आप कॉलबैक के बिना इसे प्राप्त कर सकते हैं, यहाँ कॉलबैक के बजाय वादा async प्रतीक्षा का उपयोग करें कि मैं यह कैसे करूँगा। और यहां भी मैंने त्रुटियों को संभालने के लिए दो तरीकों का वर्णन किया है

clickMe = async (value) => {
  
  // begin to wait till the message gets here;
  let {message, error} = await getMessage(value);
  
  // if error is not null
  if(error)
    return console.log('error occured ' + error);
   
  return console.log('message ' + message);

}

getMessage = (value) => {

  //returning a promise 
  return new Promise((resolve, reject) => {
  
    setTimeout(() => {
      // if passed value is 1 then it is a success
      if(value == 1){
        resolve({message: "**success**", error: null});
      }else if (value == 2){
        resolve({message: null, error: "**error**"});
      }
    }, 1000);
  
  });

}

clickWithTryCatch = async (value) => {

  try{
    //since promise reject in getMessage2 
    let message = await getMessage2(value);
    console.log('message is ' + message);
  }catch(e){
    //catching rejects from the promise
    console.log('error captured ' + e);
  }

}

getMessage2 = (value) => {

  return new Promise((resolve, reject) => {
  
    setTimeout(() => {
      if(value == 1)
        resolve('**success**');
      else if(value == 2)
        reject('**error**'); 
    }, 1000);
  
  });

}
<input type='button' value='click to trigger for a value' onclick='clickMe(1)' />
<br/>
<input type='button' value='click to trigger an error' onclick='clickMe(2)' />
<br/>
<input type='button' value='handling errors with try catch' onclick='clickWithTryCatch(1)'/>
<br/>
<input type='button' value='handling errors with try catch' onclick='clickWithTryCatch(2)'/>

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.