मैं मौजूदा कॉलबैक API को वादों में कैसे बदलूं?


721

मैं वादों के साथ काम करना चाहता हूं लेकिन मेरे पास प्रारूप में एक कॉलबैक एपीआई है जैसे:

1. डोम लोड या अन्य एक समय घटना:

window.onload; // set to callback
...
window.onload = function() {

};

2. सादा कॉलबैक:

function request(onChangeHandler) {
    ...
}
request(function() {
    // change happened
    ...
});

3. नोड शैली कॉलबैक ("नोडबैक"):

function getStuff(dat, callback) {
    ...
}
getStuff("dataParam", function(err, data) {
    ...
})

4. नोड शैली कॉलबैक के साथ एक पूरी लाइब्रेरी:

API;
API.one(function(err, data) {
    API.two(function(err, data2) {
        API.three(function(err, data3) {
            ...
        });
    });
});

मैं वादों में एपीआई के साथ कैसे काम कर सकता हूं, मैं इसे कैसे "प्रचारित" करूं?


मैंने अपना स्वयं का उत्तर पोस्ट किया, लेकिन विशिष्ट पुस्तकालय या अधिक परिस्थितियों में यह करने के लिए विस्तार करने वाले उत्तर और संपादन बहुत बहुत स्वागत करते हैं।
बेंजामिन ग्रुएनबाम

@ बर्गी यह एक दिलचस्प विचार है, मैंने एक सामान्य उत्तर देने की कोशिश की जो दो सामान्य दृष्टिकोणों (प्रोमिस कंस्ट्रक्टर और डिफ्रेंट ऑब्जेक्ट) का उपयोग करता है। मैंने जवाब में दो विकल्प देने की कोशिश की। मैं मानता हूं कि RTFMing इस मुद्दे को हल करता है, लेकिन हम इस मुद्दे पर अक्सर यहाँ और बग ट्रैकर दोनों में भाग लेते हैं, इसलिए मुझे लगा कि 'कैनोनिकल प्रश्न' लागू है - मुझे लगता है कि RTFMing JS टैग में लगभग 50% मुद्दों को हल करता है: D If आपके पास एक उत्तर में योगदान करने के लिए एक दिलचस्प अंतर्दृष्टि है या इसे संपादित करना बहुत सराहना की जाएगी।
बेंजामिन Gruenbaum

क्या कोई new Promiseऐड ओवरहेड बनाता है? मैं अपने सभी तुल्यकालिक Noje.js कार्यों को एक वचन में लपेटना चाहता हूं ताकि मेरे नोड एप्लिकेशन से सभी सिंक्रोनस कोड को हटा दें, लेकिन क्या यह सबसे अच्छा अभ्यास है? दूसरे शब्दों में, एक फ़ंक्शन जो एक स्थिर तर्क (जैसे एक स्ट्रिंग) को स्वीकार करता है और एक परिकलित परिणाम देता है, क्या मुझे उस वादे में लपेटना चाहिए? ... मैंने कहीं पढ़ा है कि आपके पास Nodejs में कोई समकालिक कोड नहीं होना चाहिए।
रॉनी रोयस्टन

1
@RonRoyston नहीं, वादों के साथ सिंक्रोनस कॉल को लपेटना एक अच्छा विचार नहीं है - केवल अतुल्यकालिक कॉल जो I / O
बेंजामिन Gruenbaum

जवाबों:


743

वादों में राज्य होता है, वे लंबित के रूप में शुरू होते हैं और इसके लिए व्यवस्थित हो सकते हैं:

  • पूरा जिसका अर्थ है कि गणना सफलतापूर्वक पूर्ण हुआ।
  • अस्वीकार कर दिया कि अभिकलन विफल हो गया।

वादा वापसी कार्यों को कभी नहीं फेंकना चाहिए, उन्हें बदले में अस्वीकार करना चाहिए। एक वादा वापसी समारोह से फेंकना आपको दोनों का उपयोग करने के लिए मजबूर करेगा} catch { और.catch । प्रॉमिस किए गए एपीआई का उपयोग करने वाले लोग वादों को फेंकने की उम्मीद नहीं करते हैं। यदि आप सुनिश्चित नहीं हैं कि JS में async API कैसे काम करती है - तो कृपया इस उत्तर को पहले देखें।

1. डोम लोड या अन्य एक समय घटना:

इसलिए, वादे बनाने का मतलब आम तौर पर निर्दिष्ट होता है जब वे बसते हैं - इसका मतलब है कि जब वे डेटा उपलब्ध है (और साथ पहुँचा जा सकता है .then) को इंगित करने के लिए पूर्ण या अस्वीकार किए गए चरण पर जाते हैं ।

आधुनिक वादों के कार्यान्वयन के साथ, जो Promiseनिर्माता को मूल ES6 वादों की तरह समर्थन करते हैं :

function load() {
    return new Promise(function(resolve, reject) {
        window.onload = resolve;
    });
}

आप तब इस तरह के परिणामस्वरूप वादे का उपयोग करेंगे:

load().then(function() {
    // Do things after onload
});

ऐसे पुस्तकालयों के साथ जो स्थगित किए जाते हैं (आइए इस उदाहरण के लिए $ q का उपयोग करें, लेकिन बाद में हम jQuery का भी उपयोग करेंगे):

function load() {
    var d = $q.defer();
    window.onload = function() { d.resolve(); };
    return d.promise;
}

या एपीआई जैसे jQuery के साथ, एक बार होने वाली घटना पर हुक करना:

function done() {
    var d = $.Deferred();
    $("#myObject").once("click",function() {
        d.resolve();
    });
    return d.promise();
}

2. सादा कॉलबैक:

ये API अच्छी तरह से सामान्य हैं ... जेएस में कॉलबैक सामान्य हैं। आइए देखते हैं कि आम मामला क्या है onSuccessऔर onFail:

function getUserData(userId, onLoad, onFail) { 

आधुनिक वादों के कार्यान्वयन के साथ, जो Promiseनिर्माता को मूल ES6 वादों की तरह समर्थन करते हैं :

function getUserDataAsync(userId) {
    return new Promise(function(resolve, reject) {
        getUserData(userId, resolve, reject);
    });
}

उन पुस्तकालयों के साथ जो स्थगित किए गए हैं (आइए इस उदाहरण के लिए jQuery का उपयोग करें, लेकिन हमने ऊपर $ q का भी उपयोग किया है):

function getUserDataAsync(userId) {
    var d = $.Deferred();
    getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });
    return d.promise();
}

jQuery भी एक $.Deferred(fn)फ़ॉर्म प्रदान करता है , जिसका हमें एक अभिव्यक्ति लिखने की अनुमति देने का लाभ है जो new Promise(fn)इस प्रकार से बहुत बारीकी से रूप का अनुकरण करता है:

function getUserDataAsync(userId) {
    return $.Deferred(function(dfrd) {
        getUserData(userId, dfrd.resolve, dfrd.reject);
    }).promise();
}

नोट: यहां हम इस तथ्य का फायदा उठाते हैं कि एक jQuery के आस्थगित resolveऔर rejectतरीके "वियोज्य" हैं; अर्थात। वे jQuery.Deferred () के उदाहरण के लिए बाध्य हैं । सभी कर्मचारी इस सुविधा की पेशकश नहीं करते हैं।

3. नोड शैली कॉलबैक ("नोडबैक"):

नोड शैली कॉलबैक (नोडबैक) का एक विशेष प्रारूप है जहां कॉलबैक हमेशा अंतिम तर्क होता है और इसका पहला पैरामीटर एक त्रुटि है। आइए पहले एक मैन्युअल रूप से प्रचारित करें:

getStuff("dataParam", function(err, data) { 

सेवा:

function getStuffAsync(param) {
    return new Promise(function(resolve, reject) {
        getStuff(param, function(err, data) {
            if (err !== null) reject(err);
            else resolve(data);
        });
    });
}

आस्थगित के साथ आप निम्नलिखित कर सकते हैं (इस उदाहरण के लिए Q का उपयोग करें, हालाँकि Q अब नए सिंटैक्स का समर्थन करता है जिसे आपको पसंद करना चाहिए ):

function getStuffAsync(param) {
    var d = Q.defer();
    getStuff(param, function(err, data) {
        if (err !== null) d.reject(err);
        else d.resolve(data);
    });
    return d.promise;   
}

सामान्य तौर पर, आपको मैन्युअल रूप से बहुत अधिक चीजों का प्रचार नहीं करना चाहिए, अधिकांश वादा पुस्तकालयों को जो नोड के साथ-साथ नोड 8 + में मूल वादों को ध्यान में रखते हुए डिजाइन किए गए थे, में नोडबैक को बढ़ावा देने के लिए एक अंतर्निहित विधि है। उदाहरण के लिए

var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
var getStuffAsync = util.promisify(getStuff); // Native promises, node only

4. नोड शैली कॉलबैक के साथ एक पूरी लाइब्रेरी:

यहां कोई सुनहरा नियम नहीं है, आप उन्हें एक-एक करके प्रॉमिस करते हैं। हालाँकि, कुछ वादे क्रियान्वयन आपको थोक में ऐसा करने की अनुमति देते हैं, उदाहरण के लिए ब्लूबर्ड में, एक नोड एपीआई को एक वादा एपीआई में परिवर्तित करना उतना ही सरल है:

Promise.promisifyAll(API);

या नोड में मूल वादों के साथ :

const { promisify } = require('util');
const promiseAPI = Object.entries(API).map(([key, v]) => ({key, fn: promisify(v)}))
                         .reduce((o, p) => Object.assign(o, {[p.key]: p.fn}), {});

टिप्पणियाँ:

  • बेशक, जब आप एक .thenहैंडलर में होते हैं तो आपको चीजों को बढ़ावा देने की आवश्यकता नहीं होती है। एक .thenहैंडलर से एक वादा वापस करना उस वादे के मूल्य के साथ हल या अस्वीकार करना होगा। एक .thenहैंडलर से फेंकना भी अच्छा अभ्यास है और इस वादे को खारिज कर देगा - यह प्रसिद्ध वादा थ्रो सेफ्टी है।
  • एक वास्तविक onloadमामले में, आपको इसके addEventListenerबजाय उपयोग करना चाहिए onX

बेंजामिन, मैंने आपके निमंत्रण को संपादित करने के लिए स्वीकार कर लिया और केस 2 में एक और jQuery का उदाहरण जोड़ दिया। इसे प्रकट होने से पहले सहकर्मी की समीक्षा करने की आवश्यकता होगी। उम्मीद है आप इसे पसंद करते हैं।
Roamer-1888

@ Roamer-1888 इसे अस्वीकार कर दिया गया क्योंकि मैंने इसे समय पर नहीं देखा और स्वीकार किया। इसके लायक यह है कि मुझे नहीं लगता कि इसके अलावा बहुत प्रासंगिक है हालांकि उपयोगी है।
बेंजामिन ग्रुएनबाम

2
बेंजामिन, या नहीं resolve()और reject()पुन: प्रयोज्य होने के लिए लिखे गए हैं, मैं उद्यम करता हूं कि मेरा सुझाया गया संपादन प्रासंगिक है क्योंकि यह प्रपत्र का एक jQuery उदाहरण प्रस्तुत करता है $.Deferred(fn), जो अन्यथा अभाव है। यदि केवल एक jQuery के उदाहरण को शामिल किया गया है, तो मैं सुझाव देता हूं कि यह इस फॉर्म का var d = $.Deferred();होना चाहिए आदि के बजाय, क्योंकि लोगों को $.Deferred(fn)इस तरह उपेक्षित रूप में tot उपेक्षित फ़ॉर्म का उपयोग करने के लिए प्रोत्साहित किया जाना चाहिए , यह इस तरह से jQuery को एक सममूल्य पर रखता है। ऐसे काम जो रिवीलिंग कंस्ट्रक्टर पैटर्न का उपयोग करते हैं ।
रोमर -1888

हे, 100% निष्पक्ष होने के लिए, मुझे नहीं पता था कि jQuery आपको करने देता है $.Deferred(fn), यदि आप संपादित करते हैं कि मौजूदा उदाहरण के बजाय अगले 15 मिनट में मुझे यकीन है कि मैं इसे समय पर अनुमोदित करने की कोशिश कर सकता हूं :)
बेंजामिन ग्रुएनबाउम

7
यह एक बेहतरीन जवाब है। आप यह भी उल्लेख करके अपडेट करना चाह सकते हैं util.promisify, कि Node.js RC 8.0.0 से शुरू होने वाले अपने मूल में जोड़ने जा रहा है। इसका काम यह ब्लूबर्ड से बहुत अलग नहीं है Promise.promisify, लेकिन इसमें अतिरिक्त निर्भरता की आवश्यकता नहीं होने का लाभ है, यदि आप सिर्फ देशी वादा चाहते हैं। मैंने उपयोग के बारे में एक ब्लॉग पोस्ट लिखी है। जो कोई भी विषय पर अधिक पढ़ना चाहता है, उसके लिए पुष्टि करें
ब्रूनो

55

आज, मैं एक सादे जावास्क्रिप्ट विधि के रूप Promiseमें उपयोग कर सकता हूं Node.js

करने के लिए एक सरल और बुनियादी उदाहरण Promise(के साथ KISS रास्ता):

सादा जावास्क्रिप्ट Async एपीआई कोड:

function divisionAPI (number, divider, successCallback, errorCallback) {

    if (divider == 0) {
        return errorCallback( new Error("Division by zero") )
    }

    successCallback( number / divider )

}

Promise जावास्क्रिप्ट Async एपीआई कोड:

function divisionAPI (number, divider) {

    return new Promise(function (fulfilled, rejected) {

        if (divider == 0) {
            return rejected( new Error("Division by zero") )
        }

        fulfilled( number / divider )

     })

}

(मैं इस सुंदर स्रोत पर जाने की सलाह देता हूं )

इसके अलावा Promiseएक साथ के साथ इस्तेमाल किया जा सकता async\awaitमें ES7एक के लिए प्रोग्राम प्रवाह प्रतीक्षा करने के लिए fullfiledनिम्नलिखित की तरह परिणाम:

function getName () {

    return new Promise(function (fulfilled, rejected) {

        var name = "John Doe";

        // wait 3000 milliseconds before calling fulfilled() method
        setTimeout ( 
            function() {
                fulfilled( name )
            }, 
            3000
        )

    })

}


async function foo () {

    var name = await getName(); // awaits for a fulfilled result!

    console.log(name); // the console writes "John Doe" after 3000 milliseconds

}


foo() // calling the foo() method to run the code

.then()विधि का उपयोग करके समान कोड के साथ एक और उपयोग

function getName () {

    return new Promise(function (fulfilled, rejected) {

        var name = "John Doe";

        // wait 3000 milliseconds before calling fulfilled() method
        setTimeout ( 
            function() {
                fulfilled( name )
            }, 
            3000
        )

    })

}


// the console writes "John Doe" after 3000 milliseconds
getName().then(function(name){ console.log(name) })

Promiseकिसी भी प्लेटफ़ॉर्म पर इस्तेमाल किया जा सकता है जो Node.js पर आधारित है react-native

बोनस : एक संकर विधि
(कॉलबैक पद्धति को त्रुटि और परिणाम के रूप में दो मानदंड हैं)

function divisionAPI (number, divider, callback) {

    return new Promise(function (fulfilled, rejected) {

        if (divider == 0) {
            let error = new Error("Division by zero")
            callback && callback( error )
            return rejected( error )
        }

        let result = number / divider
        callback && callback( null, result )
        fulfilled( result )

     })

}

उपरोक्त विधि पुराने फैशन कॉलबैक और प्रॉमिस usages के लिए परिणाम का जवाब कर सकती है।

उम्मीद है की यह मदद करेगा।


3
ये दिखाने के लिए नहीं लगता कि वादों में कैसे बदला जाए।
दिमित्री जैतसेव

33

Node.JS में वादा के रूप में एक समारोह में परिवर्तित करने से पहले

var request = require('request'); //http wrapped module

function requestWrapper(url, callback) {
    request.get(url, function (err, response) {
      if (err) {
        callback(err);
      }else{
        callback(null, response);             
      }      
    })
}


requestWrapper(url, function (err, response) {
    console.log(err, response)
})

इसे बदलने के बाद

var request = require('request');

function requestWrapper(url) {
  return new Promise(function (resolve, reject) { //returning promise
    request.get(url, function (err, response) {
      if (err) {
        reject(err); //promise reject
      }else{
        resolve(response); //promise resolve
      }
    })
  })
}


requestWrapper('http://localhost:8080/promise_request/1').then(function(response){
    console.log(response) //resolve callback(success)
}).catch(function(error){
    console.log(error) //reject callback(failure)
})

आप कई अनुरोध को संभालने की जरूरत है

var allRequests = [];
allRequests.push(requestWrapper('http://localhost:8080/promise_request/1')) 
allRequests.push(requestWrapper('http://localhost:8080/promise_request/2'))
allRequests.push(requestWrapper('http://localhost:8080/promise_request/5'))    

Promise.all(allRequests).then(function (results) {
  console.log(results);//result will be array which contains each promise response
}).catch(function (err) {
  console.log(err)
});

23

मुझे नहीं लगता कि window.onload@Benjamin द्वारा सुझाव हर समय काम करेगा, क्योंकि यह पता नहीं लगाता है कि यह लोड के बाद कहा जाता है या नहीं। मुझे वह कई बार काट चुका है। यहाँ एक संस्करण है जो हमेशा काम करना चाहिए:

function promiseDOMready() {
    return new Promise(function(resolve) {
        if (document.readyState === "complete") return resolve();
        document.addEventListener("DOMContentLoaded", resolve);
    });
}
promiseDOMready().then(initOnLoad);

1
यह सुनिश्चित करने के लिए "पहले से ही पूरा" शाखा का उपयोग नहीं करना चाहिए setTimeout(resolve, 0)(या setImmediate, यदि उपलब्ध हो) कि इसे अतुल्यकालिक कहा जाता है?
अलनीतक

5
@Alnitak resolveसमकालिक रूप से कॉल करना ठीक है। प्रॉमिस के thenहैंडलर्स को फ्रेमवर्क द्वारा अतुल्यकालिक रूप से कॉल करने की गारंटी दी जाती है , भले ही resolveउसे सिंक्रोनस कहा जाता हो।
जेफ बोमैन

15

Node.js 8.0.0 में एक नया util.promisify()API शामिल है जो मानक Node.js कॉलबैक शैली API को एक फ़ंक्शन में लिपटे रहने की अनुमति देता है जो एक वादा लौटाता है। एक उदाहरण का उपयोग util.promisify()नीचे दिखाया गया है।

const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);

readFile('/some/file')
  .then((data) => { /** ... **/ })
  .catch((err) => { /** ... **/ });

वादों के लिए बेहतर समर्थन देखें


2
इसका वर्णन करने वाले पहले से ही दो उत्तर हैं, एक तिहाई क्यों पोस्ट करें?
बेंजामिन ग्रुएनबाम

1
सिर्फ इसलिए कि नोड का वह संस्करण अब जारी किया गया है, और मैंने "आधिकारिक" फीचर विवरण और लिंक की सूचना दी है।
जियान मार्को घेरार्डी

14

Node.js 8.0.0 के लिए जारी उम्मीदवार में, एक नई उपयोगिता है, util.promisify(मैंने use.promisify के बारे में लिखा है ), जो कि किसी भी फ़ंक्शन को बढ़ावा देने की क्षमता को कूटबद्ध करता है।

यह अन्य उत्तरों में सुझाए गए दृष्टिकोणों से बहुत अलग नहीं है, लेकिन एक मुख्य विधि होने का लाभ है, और अतिरिक्त निर्भरता की आवश्यकता नहीं है।

const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);

तो फिर आप एक readFileविधि है जो एक देशी देता है Promise

readFile('./notes.txt')
  .then(txt => console.log(txt))
  .catch(...);

1
हे, आई (ओपी) ने वास्तव में util.promisifyदो बार सुझाव दिया (2014 में जब यह प्रश्न लिखा गया था, और कुछ महीने पहले - जिसे मैंने नोड के मुख्य सदस्य के रूप में धकेल दिया था और वर्तमान संस्करण जो हमारे पास नोड में है)। चूंकि यह अभी तक सार्वजनिक रूप से उपलब्ध नहीं है - मैंने इसे अभी तक इस उत्तर में नहीं जोड़ा है। हालांकि हम उपयोग प्रतिक्रिया की गहराई से सराहना करेंगे और यह जानने के लिए कि रिलीज के लिए बेहतर डॉक्स होने के लिए कुछ नुकसान क्या हैं :)
बेंजामिन ग्रुएनबाउम

1
इसके अलावा, आप util.promisifyअपने ब्लॉग पोस्ट में प्रॉमिस करने के लिए कस्टम फ्लैग पर चर्चा करना चाह सकते हैं :)
बेंजामिन ग्रुएनबाम

@BenjaminGruenbaum क्या आपके पास इस तथ्य का मतलब है कि util.promisify.customप्रतीक का उपयोग करना उपयोग के परिणाम को ओवरराइड करना संभव है। सच कहूँ तो यह एक जानबूझकर याद किया गया था, क्योंकि मैं अभी तक एक उपयोगी उपयोग के मामले को खोजने में सक्षम नहीं हूं। शायद आप मुझे कुछ इनपुट दे सकते हैं?
ब्रूनो

1
निश्चित रूप से, एपीआई fs.existsया ऐसे एपीआई पर विचार करें जो नोड कन्वेंशन का पालन नहीं करते हैं - एक ब्लूबर्ड Promise.promisify उन्हें गलत मिलेगा, लेकिन util.promisifyउन्हें सही मिलेगा ।
बेंजामिन ग्रुएनबाम

7

आप नोड जेएस के साथ जावास्क्रिप्ट देशी वादों का उपयोग कर सकते हैं।

मेरा क्लाउड 9 कोड लिंक: https://ide.c9.io/adx2803/native-promises-in-node

/**
* Created by dixit-lab on 20/6/16.
*/

var express = require('express');
var request = require('request');   //Simplified HTTP request client.


var app = express();

function promisify(url) {
    return new Promise(function (resolve, reject) {
        request.get(url, function (error, response, body) {
            if (!error && response.statusCode == 200) {
                resolve(body);
            }
            else {
                reject(error);
            }
        })
    });
}

//get all the albums of a user who have posted post 100
app.get('/listAlbums', function (req, res) {
    //get the post with post id 100
    promisify('http://jsonplaceholder.typicode.com/posts/100').then(function (result) {
        var obj = JSON.parse(result);
        return promisify('http://jsonplaceholder.typicode.com/users/' + obj.userId + '/albums')
    })
    .catch(function (e) {
        console.log(e);
    })
    .then(function (result) {
        res.end(result);
    })
})

var server = app.listen(8081, function () {
    var host = server.address().address
    var port = server.address().port

    console.log("Example app listening at http://%s:%s", host, port)
})

//run webservice on browser : http://localhost:8081/listAlbums

7

सादे पुराने वेनिला जावास्क्रिप्ट के साथ, यहाँ एक एपीआई कॉलबैक को बढ़ावा देने के लिए एक समाधान है।

function get(url, callback) {
        var xhr = new XMLHttpRequest();
        xhr.open('get', url);
        xhr.addEventListener('readystatechange', function () {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    console.log('successful ... should call callback ... ');
                    callback(null, JSON.parse(xhr.responseText));
                } else {
                    console.log('error ... callback with error data ... ');
                    callback(xhr, null);
                }
            }
        });
        xhr.send();
    }

/**
     * @function promisify: convert api based callbacks to promises
     * @description takes in a factory function and promisifies it
     * @params {function} input function to promisify
     * @params {array} an array of inputs to the function to be promisified
     * @return {function} promisified function
     * */
    function promisify(fn) {
        return function () {
            var args = Array.prototype.slice.call(arguments);
            return new Promise(function(resolve, reject) {
                fn.apply(null, args.concat(function (err, result) {
                    if (err) reject(err);
                    else resolve(result);
                }));
            });
        }
    }

var get_promisified = promisify(get);
var promise = get_promisified('some_url');
promise.then(function (data) {
        // corresponds to the resolve function
        console.log('successful operation: ', data);
}, function (error) {
        console.log(error);
});

6

Kriskowal द्वारा Q लाइब्रेरी में कॉलबैक-टू-वादा कार्य शामिल हैं। इस तरह एक विधि:

obj.prototype.dosomething(params, cb) {
  ...blah blah...
  cb(error, results);
}

Q.ninvoke के साथ परिवर्तित किया जा सकता है

Q.ninvoke(obj,"dosomething",params).
then(function(results) {
});

1
विहित उत्तर में पहले से ही उल्लेख है Q.denodeify। क्या हमें पुस्तकालय सहायकों पर जोर देने की आवश्यकता है?
बर्गी

3
मैं इसे क्यू में होनहार के बारे में एक गूगल के रूप में उपयोगी पाया गया
एड साइक्स

4

जब आपके पास कुछ कार्य होते हैं जो कॉलबैक लेते हैं और आप चाहते हैं कि वे एक वादा वापस करें, तो आप इस फ़ंक्शन का उपयोग रूपांतरण करने के लिए कर सकते हैं।

function callbackToPromise(func){

    return function(){

        // change this to use what ever promise lib you are using
        // In this case i'm using angular $q that I exposed on a util module

        var defered = util.$q.defer();

        var cb = (val) => {
            defered.resolve(val);
        }

        var args = Array.prototype.slice.call(arguments);
        args.push(cb);    
        func.apply(this, args);

        return defered.promise;
    }
}

4

नोड v7.6 + के तहत जो वादे और async में बनाया गया है:

// promisify.js
let promisify = fn => (...args) =>
    new Promise((resolve, reject) =>
        fn(...args, (err, result) => {
            if (err) return reject(err);
            return resolve(result);
        })
    );

module.exports = promisify;

कैसे इस्तेमाल करे:

let readdir = require('fs').readdir;
let promisify = require('./promisify');
let readdirP = promisify(readdir);

async function myAsyncFn(path) {
    let entries = await readdirP(path);
    return entries;
}

3

Node.js 8 में आप इस npm मॉड्यूल का उपयोग करके मक्खी पर ऑब्जेक्ट विधियों का वादा कर सकते हैं :

https://www.npmjs.com/package/doasync

यह use.promisify और Proxies का उपयोग करता है ताकि आपकी वस्तुएं अपरिवर्तित रहें। Memoization भी WeakMaps के उपयोग) के साथ किया जाता है। यहाँ कुछ उदाहरण हैं:

वस्तुओं के साथ:

const fs = require('fs');
const doAsync = require('doasync');

doAsync(fs).readFile('package.json', 'utf8')
  .then(result => {
    console.dir(JSON.parse(result), {colors: true});
  });

कार्यों के साथ:

doAsync(request)('http://www.google.com')
  .then(({body}) => {
    console.log(body);
    // ...
  });

आप मूल का भी उपयोग कर सकते हैं callऔर applyकुछ संदर्भ बाँध सकते हैं:

doAsync(myFunc).apply(context, params)
  .then(result => { /*...*/ });

2

सेट टाइमआउट से निपटने के लिए आप ES6 में मूल वचन का उपयोग कर सकते हैं :

enqueue(data) {

    const queue = this;
    // returns the Promise
    return new Promise(function (resolve, reject) {
        setTimeout(()=> {
                queue.source.push(data);
                resolve(queue); //call native resolve when finish
            }
            , 10); // resolve() will be called in 10 ms
    });

}

इस छूट में, वादे के असफल होने का कोई कारण नहीं है, इसलिए reject()इसे कभी नहीं कहा जाता है।


2

कॉलबैक शैली (Node.js में लगभग सभी समारोह इस शैली है) समारोह हमेशा इस तरह:

//fs.readdir(path[, options], callback)
fs.readdir('mypath',(err,files)=>console.log(files))

इस शैली की एक ही विशेषता है:

  1. कॉलबैक फ़ंक्शन को अंतिम तर्क द्वारा पारित किया जाता है।

  2. कॉलबैक फ़ंक्शन हमेशा त्रुटि ऑब्जेक्ट को स्वीकार करता है क्योंकि यह पहला तर्क है।

तो, आप इस तरह से इस शैली के साथ एक समारोह में परिवर्तित करने के लिए एक समारोह लिख सकते हैं:

const R =require('ramda')

/**
 * A convenient function for handle error in callback function.
 * Accept two function res(resolve) and rej(reject) ,
 * return a wrap function that accept a list arguments,
 * the first argument as error, if error is null,
 * the res function will call,else the rej function.
 * @param {function} res the function which will call when no error throw
 * @param {function} rej the function which will call when  error occur
 * @return {function} return a function that accept a list arguments,
 * the first argument as error, if error is null, the res function
 * will call,else the rej function
 **/
const checkErr = (res, rej) => (err, ...data) => R.ifElse(
    R.propEq('err', null),
    R.compose(
        res,
        R.prop('data')
    ),
    R.compose(
        rej,
        R.prop('err')
    )
)({err, data})

/**
 * wrap the callback style function to Promise style function,
 * the callback style function must restrict by convention:
 * 1. the function must put the callback function where the last of arguments,
 * such as (arg1,arg2,arg3,arg...,callback)
 * 2. the callback function must call as callback(err,arg1,arg2,arg...)
 * @param {function} fun the callback style function to transform
 * @return {function} return the new function that will return a Promise,
 * while the origin function throw a error, the Promise will be Promise.reject(error),
 * while the origin function work fine, the Promise will be Promise.resolve(args: array),
 * the args is which callback function accept
 * */
 const toPromise = (fun) => (...args) => new Promise(
    (res, rej) => R.apply(
        fun,
        R.append(
            checkErr(res, rej),
            args
        )
    )
)

अधिक संक्षिप्त उदाहरण के लिए, उदाहरण के लिए ramda.js का उपयोग किया गया है। Ramda.js कार्यात्मक प्रोग्रामिंग के लिए एक उत्कृष्ट पुस्तकालय है। उपरोक्त कोड में, हम यह प्रयोग किया जाता है लागू (जावास्क्रिप्ट की तरह function.prototype.apply) और संलग्न (जावास्क्रिप्ट की तरह function.prototype.push)। तो, अब हम कॉलबैक शैली फ़ंक्शन को शैली फ़ंक्शन का वादा करने के लिए बदल सकते हैं:

const {readdir} = require('fs')
const readdirP = toPromise(readdir)
readdir(Path)
    .then(
        (files) => console.log(files),
        (err) => console.log(err)
    )

.Promise और checkErr फ़ंक्शन berserk पुस्तकालय द्वारा स्वयं का है , यह ramda.js (मेरे द्वारा बनाएं) द्वारा एक कार्यात्मक प्रोग्रामिंग लाइब्रेरी कांटा है ।

आशा है कि यह उत्तर आपके लिए उपयोगी है।


2

आप ऐसा कुछ कर सकते हैं

// @flow

const toPromise = (f: (any) => void) => {
  return new Promise<any>((resolve, reject) => {
    try {
      f((result) => {
        resolve(result)
      })
    } catch (e) {
      reject(e)
    }
  })
}

export default toPromise

फिर इसका उपयोग करें

async loadData() {
  const friends = await toPromise(FriendsManager.loadFriends)

  console.log(friends)
}

2
अरे, मुझे यकीन नहीं है कि यह मौजूदा उत्तरों में क्या जोड़ता है (शायद स्पष्ट करें?)। इसके अलावा, वादे के निर्माता के अंदर कोशिश / पकड़ की कोई आवश्यकता नहीं है (यह आपके लिए यह स्वचालित रूप से करता है)। यह भी स्पष्ट नहीं है कि यह किस कार्य के लिए काम करता है (कि सफलता पर एक ही तर्क के साथ कॉलबैक कैसे करें? त्रुटियों को कैसे नियंत्रित किया जाता है?)
बेंजामिन ग्रुएनबाम


1

किसी callbackफ़ंक्शन का मेरा प्रॉमिसाइज़ संस्करण Pफ़ंक्शन है:

var P = function() {
  var self = this;
  var method = arguments[0];
  var params = Array.prototype.slice.call(arguments, 1);
  return new Promise((resolve, reject) => {
    if (method && typeof(method) == 'function') {
      params.push(function(err, state) {
        if (!err) return resolve(state)
        else return reject(err);
      });
      method.apply(self, params);
    } else return reject(new Error('not a function'));
  });
}
var callback = function(par, callback) {
  var rnd = Math.floor(Math.random() * 2) + 1;
  return rnd > 1 ? callback(null, par) : callback(new Error("trap"));
}

callback("callback", (err, state) => err ? console.error(err) : console.log(state))
callback("callback", (err, state) => err ? console.error(err) : console.log(state))
callback("callback", (err, state) => err ? console.error(err) : console.log(state))
callback("callback", (err, state) => err ? console.error(err) : console.log(state))

P(callback, "promise").then(v => console.log(v)).catch(e => console.error(e))
P(callback, "promise").then(v => console.log(v)).catch(e => console.error(e))
P(callback, "promise").then(v => console.log(v)).catch(e => console.error(e))
P(callback, "promise").then(v => console.log(v)).catch(e => console.error(e))

Pसमारोह की आवश्यकता है कि कॉलबैक हस्ताक्षर होना चाहिए callback(error,result)


1
इससे देश के ऊपर या उत्तर के ऊपर क्या लाभ होता है?
बेंजामिन ग्रुएनबाउम

देशी प्रॉमिस के लिए आपका क्या मतलब है?
लॉरिटोपारासी


हां हां :)। मूल विचार दिखाने के लिए बस और उदाहरण। वास्तव में आप देख सकते हैं कि मूल निवासी को भी किस प्रकार की आवश्यकता है कि फ़ंक्शन हस्ताक्षर को कुछ परिभाषित (err, value) => ...करना चाहिए या आपको एक कस्टम परिभाषित करना होगा (कस्टम प्रिमाइज्ड फ़ंक्शन देखें)। शुक्रिया गुड कैटचा।
लोरेटोपरसी

1
@loretoparisi FYI करें, var P = function (fn, ...args) { return new Promise((resolve, reject) => fn.call(this, ...args, (error, result) => error ? reject(error) : resolve(result))); };वही काम करेंगे जो आपका है और यह बहुत सरल है।
पैट्रिक रॉबर्ट्स

1

नीचे एक कार्यान्वयन (कॉलबैक एपीआई) कैसे एक वादा में परिवर्तित किया जा सकता है का कार्यान्वयन है।

function promisify(functionToExec) {
  return function() {
    var array = Object.values(arguments);
    return new Promise((resolve, reject) => {
      array.push(resolve)
      try {
         functionToExec.apply(null, array);
      } catch (error) {
         reject(error)
      }
    })
  }
}

// USE SCENARIO

function apiFunction (path, callback) { // Not a promise
  // Logic
}

var promisedFunction = promisify(apiFunction);

promisedFunction('path').then(()=>{
  // Receive the result here (callback)
})

// Or use it with await like this
let result = await promisedFunction('path');

-2

यह 5 साल की देरी की तरह है, लेकिन मैं यहां अपना प्रोमोशन संस्करण पोस्ट करना चाहता था जो कॉलबैक एपीआई से कार्य लेता है और वादों में बदल जाता है

const promesify = fn => {
  return (...params) => ({
    then: cbThen => ({
      catch: cbCatch => {
        fn(...params, cbThen, cbCatch);
      }
    })
  });
};

इस बहुत ही सरल संस्करण पर एक नज़र डालें: https://gist.github.com/jdtorregrosas/aeee96dd07558a5d18db1ff02f31e21a


1
यह एक वादा नहीं है, यह चेन नहीं करता है, कॉलबैक में डाली गई त्रुटियों से निपटें या फिर दूसरे पैरामीटर को स्वीकार करें ...
बेंजामिन ग्रुएनबाउम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.