প্রতিশ্রুতি জন্য লুপ লিখতে সঠিক উপায়।


116

নীচের প্রতিশ্রুতি কলটি এবং চেইনড লগার.লগ (পুনরায়) পুনরুক্তির মাধ্যমে সুসংগতভাবে চলমান রয়েছে তা নিশ্চিত করতে সঠিকভাবে একটি লুপ কীভাবে তৈরি করবেন ? (Bluebird)

db.getUser(email).then(function(res) { logger.log(res); }); // this is a promise

আমি নিম্নলিখিত উপায়ে চেষ্টা করেছি ( http://blog.victorquinn.com/javascript-promise- moment-loop থেকে পদ্ধতি )

var Promise = require('bluebird');

var promiseWhile = function(condition, action) {
    var resolver = Promise.defer();

    var loop = function() {
        if (!condition()) return resolver.resolve();
        return Promise.cast(action())
            .then(loop)
            .catch(resolver.reject);
    };

    process.nextTick(loop);

    return resolver.promise;
});

var count = 0;
promiseWhile(function() {
    return count < 10;
}, function() {
    return new Promise(function(resolve, reject) {
        db.getUser(email)
          .then(function(res) { 
              logger.log(res); 
              count++;
              resolve();
          });
    }); 
}).then(function() {
    console.log('all done');
}); 

যদিও এটি কাজ করে বলে মনে হচ্ছে, তবে আমি মনে করি না এটি লগার.লগ (পুনরায়) কল করার আদেশের নিশ্চয়তা দেয় ;

কোনও পরামর্শ?


1
কোডটি আমার কাছে দুর্দান্ত দেখাচ্ছে ( loopফাংশনটির সাথে পুনরাবৃত্তি সিঙ্ক্রোনাস লুপগুলি করার উপায়)। গ্যারান্টি নেই বলে আপনি কেন ভাবেন?
hugomg

db.getUser (ইমেল) যাতে ক্রমানুসারে কল করার নিশ্চয়তা দেওয়া হয়। তবে, যেহেতু db.getUser () নিজেই একটি প্রতিশ্রুতি, তাই এটি ক্রমিকভাবে কল করার অর্থ এই নয় যে প্রতিশ্রুতির অ্যাসিনক্রোনাস বৈশিষ্ট্যের কারণে 'ইমেল' এর জন্য ডাটাবেস অনুসন্ধানগুলি ক্রমান্বয়ে চলে। সুতরাং, কোন ক্যোয়ারীটি প্রথমে শেষ হবে তার উপর নির্ভর করে লগার.লগ (পুনরায়) অনুরোধ করা হয়।
ব্যবহারকারী 2127480

1
@ ব্যবহারকারী2127480: তবে প্রতিশ্রুতিটি সমাধান হওয়ার পরে লুপটির পরবর্তী পুনরাবৃত্তিটি ক্রমানুসারে বলা হয়, এই whileকোডটি কীভাবে এইভাবে কাজ করে?
বার্গি

উত্তর:


78

আমি মনে করি না এটি লগার.লগ (পুনরায়) কল করার আদেশের নিশ্চয়তা দেয়;

আসলে, এটা করে। সেই বক্তব্য resolveকল করার আগেই কার্যকর করা হয় ।

কোনও পরামর্শ?

প্রচুর। সর্বাধিক গুরুত্বপূর্ণ আপনার তৈরি-প্রতিশ্রুতি-ম্যানুয়ালি অ্যান্টিপ্যাটার্ন ব্যবহার - কেবলমাত্র করুন

promiseWhile(…, function() {
    return db.getUser(email)
             .then(function(res) { 
                 logger.log(res); 
                 count++;
             });
})…

দ্বিতীয়ত, এই whileফাংশনটি অনেক সহজ করা যায়:

var promiseWhile = Promise.method(function(condition, action) {
    if (!condition()) return;
    return action().then(promiseWhile.bind(null, condition, action));
});

তৃতীয়, আমি একটি whileলুপ (ক্লোজার ভেরিয়েবল সহ) ব্যবহার করব না তবে একটি forলুপ ব্যবহার করব:

var promiseFor = Promise.method(function(condition, action, value) {
    if (!condition(value)) return value;
    return action(value).then(promiseFor.bind(null, condition, action));
});

promiseFor(function(count) {
    return count < 10;
}, function(count) {
    return db.getUser(email)
             .then(function(res) { 
                 logger.log(res); 
                 return ++count;
             });
}, 0).then(console.log.bind(console, 'all done'));

2
উফ। ব্যতীত এটি তার যুক্তি হিসাবে actionগ্রহণ করে । সুতরাং আমাকে এত ছোট একটি সম্পাদনা করতে দেয় না। ধন্যবাদ, এটি খুব সহায়ক এবং মার্জিত। valuepromiseFor
গর্ডন

1
@ রোমের -১৮৮৮: সম্ভবত পরিভাষাটি কিছুটা অদ্ভুত, তবে আমি বলতে চাইছি একটি whileলুপ কিছু বিশ্বব্যাপী অবস্থার পরীক্ষা forকরে তবে লুপটির নিজের আয়তনের পরিবর্তনশীল (পাল্টা) লুপের দেহের সাথে আবদ্ধ থাকে। প্রকৃতপক্ষে আমি একটি আরও কার্যকরী পদ্ধতির ব্যবহার করেছি যা লুপের চেয়ে ফিক্সপয়েন্টের পুনরাবৃত্তির চেয়ে বেশি লাগে। আবার তাদের কোড পরীক্ষা করে দেখুন, valueপ্যারামিটারটি আলাদা।
বার্গি

2
ঠিক আছে, আমি এখন এটি দেখতে। যেহেতু .bind()নতুনটি আপত্তিহীন value, আমি মনে করি আমি পঠনযোগ্যতার জন্য দীর্ঘস্থায়ীভাবে কাজটি বেছে নিতে চাই। এবং দুঃখিত আমি যদি ঘন হয়ে যাচ্ছি কিন্তু যদি না থাকে promiseForএবং promiseWhileএকসাথে না থাকে তবে কীভাবে একজন অপরটিকে কল করবে?
রোমের -1888

2
@ আপনি মূলত এটিকে বাদ দিতে পারেন এবং এর return …দ্বারা প্রতিস্থাপন করতে পারেন return Promise.resolve(…)। আপনার বিরুদ্ধে অতিরিক্ত সুরক্ষা প্রয়োজন conditionবা actionএকটি ব্যতিক্রম নিক্ষেপ (যেমন Promise.methodএটি উপলব্ধ করা ), একটি পুরো ফাংশন বডির মোড়ানোreturn Promise.resolve().then(() => { … })
Bergi

2
@ ইতিমধ্যে এটি হওয়া উচিত Promise.resolve().then(action).…বা Promise.resolve(action()).…, আপনাকে ফেরতের মানটি আবৃত করতে হবে নাthen
বার্গি

134

আপনি যদি সত্যিই promiseWhen()এটির জন্য এবং অন্যান্য উদ্দেশ্যে সাধারণ ফাংশন চান , তবে বার্গির সরলীকরণগুলি ব্যবহার করে সর্বদা এটি করুন। যাইহোক, যেভাবে কাজের প্রতিশ্রুতি দেওয়ার কারণে এইভাবে কলব্যাকগুলি পাস করা সাধারণত অপ্রয়োজনীয় এবং জটিল জটিল হুপের মধ্যে দিয়ে যেতে বাধ্য করে।

যতদূর আমি বলতে পারি আপনি চেষ্টা করছেন:

  • ইমেল ঠিকানা সংগ্রহের জন্য অবিচ্ছিন্নভাবে একাধিক ব্যবহারকারীর বিবরণ আনতে (কমপক্ষে, এটি কেবলমাত্র দৃশ্যে পরিণত হয়)।
  • .then()পুনরাবৃত্তি মাধ্যমে একটি চেইন নির্মাণ করে এটি করতে ।
  • ফিরে আসা ফলাফলগুলি পরিচালনা করার সময় মূল ক্রম বজায় রাখতে।

এইভাবে সংজ্ঞায়িত করা হয়েছে, সমস্যাটি প্রকৃতপক্ষে অ্যান্টি-প্যাটার্নগুলির প্রতিশ্রুতিতে "কালেকশন কেরফফল" এর আওতায় আলোচিত একটি , যা দুটি সহজ সমাধান দেয়:

  • সমান্তরাল অ্যাসিক্রোনাস কলগুলি ব্যবহার করে Array.prototype.map()
  • সিরিয়াল অ্যাসিক্রোনাস কল ব্যবহার করে Array.prototype.reduce()

সমান্তরাল পদ্ধতির (সরলভাবে) আপনি যে বিষয়টি এড়াতে চেষ্টা করছেন তা দেবে - প্রতিক্রিয়াগুলির ক্রমটি অনিশ্চিত। সিরিয়াল পদ্ধতির প্রয়োজনীয় .then()চেইন তৈরি হবে - ফ্ল্যাট - কোনও পুনরাবৃত্তি হবে না।

function fetchUserDetails(arr) {
    return arr.reduce(function(promise, email) {
        return promise.then(function() {
            return db.getUser(email).done(function(res) {
                logger.log(res);
            });
        });
    }, Promise.resolve());
}

নীচে কল করুন:

//Compose here, by whatever means, an array of email addresses.
var arrayOfEmailAddys = [...];

fetchUserDetails(arrayOfEmailAddys).then(function() {
    console.log('all done');
});

আপনি দেখতে পাচ্ছেন, কুৎসিত বাইরের ভের countবা এর সাথে সম্পর্কিত conditionফাংশনের দরকার নেই। সীমা (প্রশ্নের 10 টি) অ্যারের দৈর্ঘ্য দ্বারা সম্পূর্ণ নির্ধারিত হয় arrayOfEmailAddys


16
এটি নির্বাচিত উত্তর হওয়া উচিত বলে মনে হয়। সুদৃশ্য এবং খুব পুনরায় ব্যবহারযোগ্য পদ্ধতির
কেন

1
কেউ কি জানেন যে কোনও ধরা পরে পিতামাতার কাছে প্রচার করবে? উদাহরণস্বরূপ, যদি db.getUser ব্যর্থ হয়, (প্রত্যাখ্যান) ত্রুটি ব্যাক আপ প্রচার করবে?
ওয়েফোথফিউচার

@ ওয়েফথফিউচার, না এভাবে চিন্তা করুন ..... আপনি ইতিহাস পরিবর্তন করতে পারবেন না।
রোমের -1888

4
উত্তর করার জন্য ধন্যবাদ. এটি গ্রহণযোগ্য উত্তর হওয়া উচিত।
klvs

1
@ রোমের -1888 আমার ভুল, আমি মূল প্রশ্নটি ভুলভাবে লিখেছি। আমি (ব্যক্তিগতভাবে) একটি সমাধান সন্ধান করছিলাম যেখানে আপনার অনুরোধগুলি নিষ্পত্তির সাথে সাথে আপনার প্রয়োজনীয় অন্তর্নিহিত তালিকাটি বাড়ছে (এটি একটি ডিবি-র আরও একটি কোয়েরি)। এই ক্ষেত্রে আমি একটি জেনারেটরের সাথে হ্রাস ব্যবহারের ধারণাটি পেয়েছি (১) প্রতিশ্রুতি শৃঙ্খলার শর্তসাপেক্ষ বর্ধন এবং (২) প্রত্যাবর্তিত ফলাফলগুলির ব্যবহার।
jhp

40

আমি এখানে স্ট্যান্ডার্ড প্রোমিস অবজেক্টটি দিয়ে কীভাবে করব।

// Given async function sayHi
function sayHi() {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log('Hi');
      resolve();
    }, 3000);
  });
}

// And an array of async functions to loop through
const asyncArray = [sayHi, sayHi, sayHi];

// We create the start of a promise chain
let chain = Promise.resolve();

// And append each function in the array to the promise chain
for (const func of asyncArray) {
  chain = chain.then(func);
}

// Output:
// Hi
// Hi (After 3 seconds)
// Hi (After 3 more seconds)

দুর্দান্ত উত্তর @ ইয়ংওয়ার্থ
জাম

3
এভাবে কীভাবে প্যারাম প্রেরণ করবেন?
আকাশ খান

4
@ খাঁ চেইনে = চেইন.থেন (ফানক) লাইনে আপনি যা করতে পারেন: chain = chain.then(func.bind(null, "...your params here")); বা chain = chain.then(() => func("your params here"));
ইয়ংওয়ার্থ

9

প্রদত্ত

  • asyncFn ফাংশন
  • আইটেমের অ্যারে

প্রয়োজনীয়

  • অঙ্গীকার চেইন।
  • নেটিভ es6

সমাধান

let asyncFn = (item) => {
  return new Promise((resolve, reject) => {
    setTimeout( () => {console.log(item); resolve(true)}, 1000 )
  })
}

// asyncFn('a')
// .then(()=>{return async('b')})
// .then(()=>{return async('c')})
// .then(()=>{return async('d')})

let a = ['a','b','c','d']

a.reduce((previous, current, index, array) => {
  return previous                                    // initiates the promise chain
  .then(()=>{return asyncFn(array[index])})      //adds .then() promise for each item
}, Promise.resolve())

2
যদি asyncজাভাস্ক্রিপ্টে কোনও সংরক্ষিত শব্দ হয়ে উঠতে পারে তবে এটি এখানে ফাংশনটির নাম পরিবর্তন করতে স্বচ্ছতা যুক্ত করতে পারে।
হিপ্পিট্রেইল

এছাড়াও, এটি কি এমন নয় যে ব্রেসযুক্ত দেহ ছাড়াই ফ্যাট অ্যার ফাংশনগুলি কেবল সেখানে প্রকাশের মূল্যায়ন যা ফিরিয়ে দেয়? এটি কোডটিকে আরও সংক্ষিপ্ত করে তুলবে। আমি একটি মন্তব্যও যুক্ত করতে পারি currentযা অব্যবহৃত রয়েছে ating
হিপ্পিট্রেইল

2
এই সঠিক উপায়!
টেলিমে.ইও

4

এটি সমাধানের জন্য একটি নতুন উপায় রয়েছে এবং এটি অ্যাসিঙ্ক / অপেক্ষা করুন।

async function myFunction() {
  while(/* my condition */) {
    const res = await db.getUser(email);
    logger.log(res);
  }
}

myFunction().then(() => {
  /* do other stuff */
})

https://developer.mozilla.org/en-US/docs/Web/JavaScript/References/Statesments/async_function https://ponyfoo.com/articles/ বোঝা- জাভাস্ক্রিপ্ট- ধারণার সাথে সংযুক্ত করুন-


আপনাকে ধন্যবাদ, এটি কোনও ফ্রেমওয়ার্ক (ব্লুবার্ড) ব্যবহারের সাথে জড়িত নয়।
রল্ফ

3

বার্গির প্রস্তাবিত ফাংশনটি সত্যিই দুর্দান্ত:

var promiseWhile = Promise.method(function(condition, action) {
      if (!condition()) return;
    return action().then(promiseWhile.bind(null, condition, action));
});

তবুও আমি প্রতিশ্রুতিগুলি ব্যবহার করার সময় একটি ছোট সংযোজন করতে চাই, যা বোঝায়:

var promiseWhile = Promise.method(function(condition, action, lastValue) {
  if (!condition()) return lastValue;
  return action().then(promiseWhile.bind(null, condition, action));
});

এইভাবে লুপটি একটি প্রতিশ্রুতি শৃঙ্খলে এম্বেড করা যেতে পারে এবং লাস্টভ্যালুর সাথে সমাধান করা যায় (এছাড়াও যদি ক্রিয়াটি (কখনও চালিত না হয়))। উদাহরণ দেখুন:

var count = 10;
util.promiseWhile(
  function condition() {
    return count > 0;
  },
  function action() {
    return new Promise(function(resolve, reject) {
      count = count - 1;
      resolve(count)
    })
  },
  count)

3

আমি এই জাতীয় কিছু তৈরি করব:

var request = []
while(count<10){
   request.push(db.getUser(email).then(function(res) { return res; }));
   count++
};

Promise.all(request).then((dataAll)=>{
  for (var i = 0; i < dataAll.length; i++) {

      logger.log(dataAll[i]); 
  }  
});

এইভাবে, ডেটাআল সমস্ত লগিনের জন্য একটি আদেশযুক্ত অ্যারে ordered এবং সমস্ত প্রতিশ্রুতি করা হলে লগ অপারেশন সম্পাদন করবে।


প্রতিশ্রুতি। একই সময়ে কলগুলি প্রতিশ্রুতি দেবে। সুতরাং সমাপ্তির ক্রম পরিবর্তন হতে পারে। প্রশ্ন জড়িত প্রতিশ্রুতি জিজ্ঞাসা। সুতরাং সমাপ্তির ক্রম পরিবর্তন করা উচিত নয়।
ক্যানব্যাক্স

সম্পাদনা 1: আপনার কাছে প্রমিস.এলকে কল করার দরকার নেই। যতক্ষণ প্রতিশ্রুতিগুলি বরখাস্ত করা হয় ততক্ষণ তাদের সমান্তরালে কার্যকর করা হবে।
ক্যানব্যাক্স

1

অ্যাসিঙ্কটি ব্যবহার করুন এবং অপেক্ষা করুন (এস 6):

function taskAsync(paramets){
 return new Promise((reslove,reject)=>{
 //your logic after reslove(respoce) or reject(error)
})
}

async function fName(){
let arry=['list of items'];
  for(var i=0;i<arry.length;i++){
   let result=await(taskAsync('parameters'));
}

}

0
function promiseLoop(promiseFunc, paramsGetter, conditionChecker, eachFunc, delay) {
    function callNext() {
        return promiseFunc.apply(null, paramsGetter())
            .then(eachFunc)
    }

    function loop(promise, fn) {
        if (delay) {
            return new Promise(function(resolve) {
                setTimeout(function() {
                    resolve();
                }, delay);
            })
                .then(function() {
                    return promise
                        .then(fn)
                        .then(function(condition) {
                            if (!condition) {
                                return true;
                            }
                            return loop(callNext(), fn)
                        })
                });
        }
        return promise
            .then(fn)
            .then(function(condition) {
                if (!condition) {
                    return true;
                }
                return loop(callNext(), fn)
            })
    }

    return loop(callNext(), conditionChecker);
}


function makeRequest(param) {
    return new Promise(function(resolve, reject) {
        var req = https.request(function(res) {
            var data = '';
            res.on('data', function (chunk) {
                data += chunk;
            });
            res.on('end', function () {
                resolve(data);
            });
        });
        req.on('error', function(e) {
            reject(e);
        });
        req.write(param);
        req.end();
    })
}

function getSomething() {
    var param = 0;

    var limit = 10;

    var results = [];

    function paramGetter() {
        return [param];
    }
    function conditionChecker() {
        return param <= limit;
    }
    function callback(result) {
        results.push(result);
        param++;
    }

    return promiseLoop(makeRequest, paramGetter, conditionChecker, callback)
        .then(function() {
            return results;
        });
}

getSomething().then(function(res) {
    console.log('results', res);
}).catch(function(err) {
    console.log('some error along the way', err);
});


0

এখানে অন্য পদ্ধতি (ES6 ডাব্লু / স্ট্যান্ড প্রতিশ্রুতি) দেওয়া আছে। লোডাশ / আন্ডারস্কোর প্রকারের প্রস্থান মাপদণ্ড ব্যবহার করে (প্রত্যাবর্তন === মিথ্যা)। নোট করুন যে আপনি doOne () এ চালানোর বিকল্পগুলিতে সহজেই একটি প্রস্থানক () পদ্ধতি যুক্ত করতে পারেন।

const whilePromise = (fnReturningPromise,options = {}) => { 
    // loop until fnReturningPromise() === false
    // options.delay - setTimeout ms (set to 0 for 1 tick to make non-blocking)
    return new Promise((resolve,reject) => {
        const doOne = () => {
            fnReturningPromise()
            .then((...args) => {
                if (args.length && args[0] === false) {
                    resolve(...args);
                } else {
                    iterate();
                }
            })
        };
        const iterate = () => {
            if (options.delay !== undefined) {
                setTimeout(doOne,options.delay);
            } else {
                doOne();
            }
        }
        Promise.resolve()
        .then(iterate)
        .catch(reject)
    })
};

0

স্ট্যান্ডার্ড প্রতিশ্রুতি অবজেক্ট ব্যবহার করা এবং প্রতিশ্রুতি থাকা ফলাফলগুলি ফিরিয়ে দেয়।

function promiseMap (data, f) {
  const reducer = (promise, x) =>
    promise.then(acc => f(x).then(y => acc.push(y) && acc))
  return data.reduce(reducer, Promise.resolve([]))
}

var emails = []

function getUser(email) {
  return db.getUser(email)
}

promiseMap(emails, getUser).then(emails => {
  console.log(emails)
})

0

প্রথমে প্রতিশ্রুতির অ্যারে (প্রতিশ্রুতি অ্যারে) নিন এবং এই প্রতিশ্রুতি অ্যারেটি ব্যবহার করে সমাধান করার পরে Promise.all(promisearray)

var arry=['raju','ram','abdul','kruthika'];

var promiseArry=[];
for(var i=0;i<arry.length;i++) {
  promiseArry.push(dbFechFun(arry[i]));
}

Promise.all(promiseArry)
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
     console.log(error);
  });

function dbFetchFun(name) {
  // we need to return a  promise
  return db.find({name:name}); // any db operation we can write hear
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.