javascript - मैं मौजूदा कॉलबैक एपीआई को वादे के लिए कैसे परिवर्तित करूं?




node.js callback (12)

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

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

यह use.promisify और प्रॉक्सी का उपयोग करता है ताकि आपकी वस्तुएं अपरिवर्तित रहें। 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 लिए apply कर सकते हैं:

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

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

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

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


Node.js 8.0.0 के लिए रिलीज उम्मीदवार में, एक नई उपयोगिता है, util.promisify (मैंने util.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(...);

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

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 )

     })

}

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

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

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 उपयोग किसी भी मंच पर भी किया जा सकता है जो react-native जैसे नोड.जेएस पर आधारित react-native

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


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

मेरा क्लाउड 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

आप सेटटाइमआउट से निपटने के लिए ईएस 6 में देशी वादा का उपयोग कर सकते हैं:

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() कभी नहीं कहा जाता है।


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

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

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

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

नोड 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;
}

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

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

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

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

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)


कॉलबैक स्टाइल फ़ंक्शन हमेशा इस तरह (लगभग 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)
    )

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

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


नोड.जेएस में वादे के रूप में एक समारोह को बदलने से पहले

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

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


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

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

var request = require('request');
var Promise = require('bluebird');

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






bluebird