ES6 এর প্রতিশ্রুতি.ল () ব্যবহার করার সময় সম্মতিটি সীমাবদ্ধ করার সর্বোত্তম উপায় কী?


98

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

এই কোডটির সংক্ষিপ্ত সংস্করণটি বর্তমানে এর মতো কিছু দেখাচ্ছে ...

function getCounts() {
  return users.map(user => {
    return new Promise(resolve => {
      remoteServer.getCount(user) // makes an HTTP request
      .then(() => {
        /* snip */
        resolve();
      });
    });
  });
}

Promise.all(getCounts()).then(() => { /* snip */});

এই কোডটি নোড ৪.৩.২ এ চলছে। পুনরাবৃত্তি করার জন্য, Promise.allএমন কোনও ব্যবস্থা নেওয়া যেতে পারে যাতে নির্দিষ্ট সময়ে প্রতিশ্রুতি সংখ্যক নির্দিষ্ট সময়ে কোনও অগ্রগতি হয়?



4
ভুলে যাবেন না যে Promise.allপ্রতিশ্রুতি অগ্রগতি পরিচালনা করে - প্রতিশ্রুতিগুলি তারা নিজেরাই করে, Promise.allকেবল তাদের জন্য অপেক্ষা করে।
বার্গি


উত্তর:


51

মনে রাখবেন যে Promise.all()প্রতিশ্রুতিগুলি তাদের কাজ শুরু করার জন্য ট্রিগার করে না, প্রতিশ্রুতি নিজেই তা তৈরি করে।

এটি মনে রেখে, একটি সমাধান হ'ল যখনই কোনও প্রতিশ্রুতি সমাধান হয়ে যায় তখনই নতুন প্রতিশ্রুতি শুরু করা উচিত বা আপনি ইতিমধ্যে সীমাতে রয়েছেন কিনা তা পরীক্ষা করা।

যাইহোক, এখানে চাকা পুনরায় উদ্ভাবন করার প্রয়োজন নেই। আপনি এই উদ্দেশ্যে যে লাইব্রেরিটি ব্যবহার করতে পারেন তা হ'লes6-promise-pool । তাদের উদাহরণ থেকে:

// On the Web, leave out this line and use the script tag above instead. 
var PromisePool = require('es6-promise-pool')

var promiseProducer = function () {
  // Your code goes here. 
  // If there is work left to be done, return the next work item as a promise. 
  // Otherwise, return null to indicate that all promises have been created. 
  // Scroll down for an example. 
}

// The number of promises to process simultaneously. 
var concurrency = 3

// Create a pool. 
var pool = new PromisePool(promiseProducer, concurrency)

// Start the pool. 
var poolPromise = pool.start()

// Wait for the pool to settle. 
poolPromise.then(function () {
  console.log('All promises fulfilled')
}, function (error) {
  console.log('Some promise rejected: ' + error.message)
})

25
দুর্ভাগ্যজনক যে এস -6-প্রতিশ্রুতি-পুলটি প্রতিশ্রুতিগুলি ব্যবহারের পরিবর্তে পুনরায় নতুন করে তোলে। আমি পরিবর্তে এই সংক্ষিপ্ত সমাধানটি প্রস্তাব দিই (যদি আপনি ইতিমধ্যে ES6 বা ES7 ব্যবহার করছেন) github.com/rxaviers/async-pool
রাফায়েল জাভিয়ার

4
দু'দিকে একবার দেখে, অ্যাসিঙ্ক-পুলটি আরও ভাল দেখায়! আরও সোজা এগিয়ে এবং আরও লাইটওয়েট।
অন্তহীন

4
আমি সর্বাধিক সাধারণ বাস্তবায়ন হতে পি-সীমাও পেয়েছি। নীচে আমার উদাহরণ দেখুন। stackoverflow.com/a/52262024/8177355
ম্যাথু রাইডআউট

4
আমি মনে করি, প্রতিশ্রুতিগুলির চুক্তি সীমাবদ্ধ করার জন্য ক্ষুদ্র-অ্যাসাইক-পুলটি অনেক বেশি ভাল, অ-হস্তক্ষেপমূলক এবং প্রাকৃতিক সমাধান।
সানি টম্বি

73

পি-সীমা

আমি প্রতিশ্রুতি সম্মতি সীমাবদ্ধতার তুলনা করেছি একটি কাস্টম স্ক্রিপ্ট, ব্লুবার্ড, এস 6-প্রতিশ্রুতি-পুল এবং পি-সীমা দিয়ে। আমি বিশ্বাস করি যে পি-সীমাটির এই প্রয়োজনের জন্য সবচেয়ে সহজ, প্রত্যাহারযোগ্য বাস্তবায়ন রয়েছে। তাদের ডকুমেন্টেশন দেখুন

প্রয়োজনীয়তা

উদাহরণ হিসাবে async সঙ্গে সামঞ্জস্যপূর্ণ হতে

আমার উদাহরণ

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

const pLimit = require('p-limit');

// Example Concurrency of 3 promise at once
const limit = pLimit(3);

let urls = [
    "http://www.exampleone.com/",
    "http://www.exampletwo.com/",
    "http://www.examplethree.com/",
    "http://www.examplefour.com/",
]

// Create an array of our promises using map (fetchData() returns a promise)
let promises = urls.map(url => {

    // wrap the function we are calling in the limit function we defined above
    return limit(() => fetchData(url));
});

(async () => {
    // Only three promises are run at once (as defined above)
    const result = await Promise.all(promises);
    console.log(result);
})();

কনসোল লগ ফলাফলটি আপনার সমাধান হওয়া প্রতিশ্রুতি প্রতিক্রিয়া ডেটার একটি অ্যারে।


4
এই এক জন্য ধন্যবাদ! এটি একটি খুব সহজ
জন

4
এটি একযোগে অনুরোধগুলি সীমাবদ্ধ করার জন্য আমি দেখেছি এখন পর্যন্ত সেরা গ্রন্থাগার। এবং দুর্দান্ত উদাহরণ, ধন্যবাদ!
ক্রিস Livdahl

4
তুলনা করার জন্য ধন্যবাদ। আপনি কি github.com/rxaviers/async-pool এর সাথে তুলনা করেছেন ?
অহং

4
ব্যবহার করা সহজ, দুর্দান্ত পছন্দ।
drmrbrewer

22

ব্যবহার Array.prototype.splice

while (funcs.length) {
  // 100 at at time
  await Promise.all( funcs.splice(0, 100).map(f => f()) )
}

4
এটি একটি অবমূল্যায়িত সমাধান। সরলতা পছন্দ।
ব্র্যানন

8
এটি পুলের পরিবর্তে ব্যাচগুলিতে ফাংশন পরিচালনা করে, যেখানে অন্য ফাংশন শেষ হওয়ার সাথে সাথে একটি ফাংশন তত্ক্ষণাত ডাকা হয়।
ক্লটস্যাং

এই সমাধান পছন্দ!
প্রসুন

চারপাশে আরও প্রসঙ্গের অভাব নিয়ে এটি কী করছে তা উপলব্ধি করার জন্য একটি সেকেন্ড নিয়েছিল, যেমন এটি পুলের পরিবর্তে কোনও ব্যাচকে মৌমাছির মতো করে ing আপনি শুরু থেকে মাঝখানে ছড়িয়ে ছিটিয়ে প্রতিবারই অ্যারেটিকে পুনরায় অর্ডার করছেন। (ব্রাউজারটি সমস্ত আইটেমকে পুনরায় সূচনা করতে হবে) একটি তাত্ত্বিক পারফরম্যান্স আরও ভাল বিকল্প বিকল্প হ'ল এর পরিবর্তে শেষ থেকে স্টাফ নেওয়া arr.splice(-100)যদি আদেশের ডোজটি ম্যাথার না হয় তবে আপনি অ্যারেটিকে বিপরীত করতে পারেন: পি
এন্ডলেস

ব্যাচে দৌড়ানোর জন্য খুব দরকারী useful দ্রষ্টব্য: বর্তমান ব্যাচটি 100% সম্পূর্ণ না হওয়া পর্যন্ত পরবর্তী ব্যাচ শুরু হবে না।
কেসি ডোয়েন

20

যদি আপনি জানেন যে পুনরাবৃত্তিগুলি কীভাবে কাজ করে এবং কীভাবে সেগুলি গ্রাস করা হয় আপনার কোনও অতিরিক্ত গ্রন্থাগারের দরকার পড়বে না, যেহেতু এটি নিজেই নিজের সম্মতিটি তৈরি করা খুব সহজ হয়ে উঠতে পারে। আমাকে প্রদর্শন করুন:

/* [Symbol.iterator]() is equivalent to .values()
const iterator = [1,2,3][Symbol.iterator]() */
const iterator = [1,2,3].values()


// loop over all items with for..of
for (const x of iterator) {
  console.log('x:', x)
  
  // notices how this loop continues the same iterator
  // and consumes the rest of the iterator, making the
  // outer loop not logging any more x's
  for (const y of iterator) {
    console.log('y:', y)
  }
}

আমরা একই পুনরুক্তি ব্যবহার করতে এবং এটি কর্মীদের মধ্যে ভাগ করতে পারি।

আপনি যদি আপনার .entries()পরিবর্তে ব্যবহার করে থাকেন তবে 2 .values()ডি অ্যারে পেয়েছেন [[index, value]]যা দিয়ে আমি নীচের সাথে 2 এর সম্মতি দিয়ে প্রদর্শন করব

const sleep = t => new Promise(rs => setTimeout(rs, t))

async function doWork(iterator) {
  for (let [index, item] of iterator) {
    await sleep(1000)
    console.log(index + ': ' + item)
  }
}

const iterator = Array.from('abcdefghij').entries()
const workers = new Array(2).fill(iterator).map(doWork)
//    ^--- starts two workers sharing the same iterator

Promise.allSettled(workers).then(() => console.log('done'))

এর সুবিধাটি হ'ল আপনি একবারে সবকিছু প্রস্তুত না করে জেনারেটরের কাজ করতে পারেন ।


দ্রষ্টব্য: উদাহরণস্বরূপ অ্যাসিঙ্ক-পুলের তুলনায় এটির থেকে পৃথকটি হ'ল এটি দুটি শ্রমিককে উত্সাহিত করে, তাই যদি কোনও শ্রমিক সূচক 5 বলার কারণে কোনও কারণে কোনও ত্রুটি ছুড়ে দেয় তবে এটি অন্য শ্রমিককে বাকী কাজ করা থেকে বিরত রাখবে না। সুতরাং আপনি 2 সমাবর্তন করা থেকে নিচে 1 এ চলে যান (সুতরাং এটি সেখানে থামবে না) সুতরাং আমার পরামর্শটি হ'ল doWorkফাংশনের অভ্যন্তরে সমস্ত ত্রুটি ধরা


এটা সত্যিই দারুন! ধন্যবাদ অন্তহীন!
ব্যবহারকারী 3413723

এটি অবশ্যই একটি দুর্দান্ত পদ্ধতির! আপনি অতিরিক্ত হিসাবে শেষ হতে পারে তা নিশ্চিত করুন যে আপনার চুক্তিটি আপনার কার্য তালিকার দৈর্ঘ্যের অতিক্রম করবে না (যদি আপনি যাইহোক ফলাফলের বিষয়ে যত্নশীল হন)!
ক্রিস ওয়ে

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

16

Bluebird এর Promise.map কিভাবে অনেক প্রতিশ্রুতি সমান্তরাল চলমান হবে নিয়ন্ত্রণ করার জন্য একটি সম্পাতবিন্দু বিকল্প গ্রহণ করতে পারেন। কখনও কখনও এটি আরও সহজ .allকারণ আপনার প্রতিশ্রুতি অ্যারে তৈরি করার প্রয়োজন নেই।

const Promise = require('bluebird')

function getCounts() {
  return Promise.map(users, user => {
    return new Promise(resolve => {
      remoteServer.getCount(user) // makes an HTTP request
      .then(() => {
        /* snip */
        resolve();
       });
    });
  }, {concurrency: 10}); // <---- at most 10 http requests at a time
}

আপনার যদি দ্রুত প্রতিশ্রুতি এবং one 18 কেবি অতিরিক্ত জাঙ্কের প্রয়োজন হয় তবে ব্লুবার্ড কৃতজ্ঞ হয়;) যদি আপনি কেবল একটি জিনিসের জন্য এটি ব্যবহার করেন;)
অন্তহীন

4
আপনার পক্ষে এক জিনিস কতটা গুরুত্বপূর্ণ এবং যদি আরও দ্রুত / সহজতর উপায় থাকে তবে তা নির্ভর করে। একটি সাধারণ বাণিজ্য বন্ধ। আমি ব্যবহারের সহজতা এবং কয়েকটি কেবিতে ফাংশন বেছে নেব, তবে ওয়াইএমএমভি।
জিংসওও চেন

11

HTTP অনুরোধ সীমাবদ্ধ করার প্রতিশ্রুতি ব্যবহারের পরিবর্তে নোডের অন্তর্নির্মিত http.Agent.maxSocket ব্যবহার করুন । এটি একটি লাইব্রেরি ব্যবহার করার বা আপনার নিজস্ব পুলিং কোড লেখার প্রয়োজনীয়তা সরিয়ে দেয় এবং আপনি কী সীমাবদ্ধ করছেন তার উপর অতিরিক্ত সুবিধা আরও নিয়ন্ত্রণ করে।

এজেন্ট.ম্যাকসকেটস

ডিফল্টরূপে ইনফিনিটিতে সেট করুন। এজেন্ট কতগুলি সাম্প্রতিক সকেট উত্স প্রতি খুলতে পারে তা নির্ধারণ করে। উত্স হয় হয় 'হোস্ট: পোর্ট' বা 'হোস্ট: পোর্ট: লোকালএড্রেস' সমন্বয়।

উদাহরণ স্বরূপ:

var http = require('http');
var agent = new http.Agent({maxSockets: 5}); // 5 concurrent connections per origin
var request = http.request({..., agent: agent}, ...);

একই উত্সে একাধিক অনুরোধ করা থাকলে, এটি আপনাকে সত্যতে সেট করতেও উপকৃত হতে পারে keepAlive(আরও তথ্যের জন্য উপরের ডক্স দেখুন)।


11
তবুও, তত্ক্ষণাত হাজার হাজার ক্লোজার তৈরি করা এবং সকেটগুলি পুল করা খুব কার্যকর বলে মনে হচ্ছে না?
বার্গি

3

আমি লাইব্রেরিটি অ্যাসিঙ্ক-পুলের পরামর্শ দিই: https://github.com/rxaviers/async-pool

npm install tiny-async-pool

বর্ণনা:

নেটিভ ES6 / ES7 ব্যবহার করে সীমিত সম্মতিতে একাধিক প্রতিশ্রুতি-রিটার্নিং এবং অ্যাসিঙ্ক ফাংশনগুলি চালান

asyncPool সীমাবদ্ধ সমঝোতা পুলে একাধিক প্রতিশ্রুতি-প্রত্যাবর্তন এবং async ফাংশন পরিচালনা করে। এটি প্রতিশ্রুতি প্রত্যাখ্যান করার সাথে সাথে তা প্রত্যাখ্যান করে। সমস্ত প্রতিশ্রুতি পূর্ণ হলে এটি সমাধান হয়। এটি যত তাড়াতাড়ি সম্ভব পুনরাবৃত্তির ক্রিয়াকলাপটিকে ডাকবে (সমঝোতার সীমাতে)।

ব্যবহার:

const timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i));
await asyncPool(2, [1000, 5000, 3000, 2000], timeout);
// Call iterator (i = 1000)
// Call iterator (i = 5000)
// Pool limit of 2 reached, wait for the quicker one to complete...
// 1000 finishes
// Call iterator (i = 3000)
// Pool limit of 2 reached, wait for the quicker one to complete...
// 3000 finishes
// Call iterator (i = 2000)
// Itaration is complete, wait until running ones complete...
// 5000 finishes
// 2000 finishes
// Resolves, results are passed in given array order `[1000, 5000, 3000, 2000]`.

4
আমার জন্য কাজ কর. ধন্যবাদ এটি দুর্দান্ত লাইব্রেরি।
সানি টম্বি

2

এটি পুনরাবৃত্তি ব্যবহার করে সমাধান করা যেতে পারে।

ধারণাটি হ'ল প্রাথমিকভাবে আপনি সর্বাধিক অনুমোদিত সংখ্যক অনুরোধগুলি প্রেরণ করুন এবং এই অনুরোধগুলির প্রত্যেকটির পুনরাবৃত্তভাবে এর সমাপ্তির পরে নিজেকে প্রেরণ করা চালিয়ে যেতে হবে।

function batchFetch(urls, concurrentRequestsLimit) {
    return new Promise(resolve => {
        var documents = [];
        var index = 0;

        function recursiveFetch() {
            if (index === urls.length) {
                return;
            }
            fetch(urls[index++]).then(r => {
                documents.push(r.text());
                if (documents.length === urls.length) {
                    resolve(documents);
                } else {
                    recursiveFetch();
                }
            });
        }

        for (var i = 0; i < concurrentRequestsLimit; i++) {
            recursiveFetch();
        }
    });
}

var sources = [
    'http://www.example_1.com/',
    'http://www.example_2.com/',
    'http://www.example_3.com/',
    ...
    'http://www.example_100.com/'
];
batchFetch(sources, 5).then(documents => {
   console.log(documents);
});

2

এখানে একটি অনুলিপি-প্রচ্ছন্ন বন্ধুত্বপূর্ণ এবং বৈশিষ্ট্য সম্পূর্ণ Promise.all()/ map()বিকল্প, সম্মতিসীমা সীমা সহ আমার ES7 সমাধান ।

Promise.all()এটি অনুরূপ রিটার্ন অর্ডার বজায় রাখার পাশাপাশি অ-প্রতিশ্রুতি ফেরতের মানগুলির জন্য একটি ফলব্যাক।

আমি বিভিন্ন বাস্তবায়নের তুলনাও অন্তর্ভুক্ত করেছি কারণ এটি অন্যান্য দিকগুলির কয়েকটি সমাধান মিস করেছে বলে কিছু দিক বর্ণনা করে।

ব্যবহার

const asyncFn = delay => new Promise(resolve => setTimeout(() => resolve(), delay));
const args = [30, 20, 15, 10];
await asyncPool(args, arg => asyncFn(arg), 4); // concurrency limit of 4

বাস্তবায়ন

async function asyncBatch(args, fn, limit = 8) {
  // Copy arguments to avoid side effects
  args = [...args];
  const outs = [];
  while (args.length) {
    const batch = args.splice(0, limit);
    const out = await Promise.all(batch.map(fn));
    outs.push(...out);
  }
  return outs;
}

async function asyncPool(args, fn, limit = 8) {
  return new Promise((resolve) => {
    // Copy arguments to avoid side effect, reverse queue as
    // pop is faster than shift
    const argQueue = [...args].reverse();
    let count = 0;
    const outs = [];
    const pollNext = () => {
      if (argQueue.length === 0 && count === 0) {
        resolve(outs);
      } else {
        while (count < limit && argQueue.length) {
          const index = args.length - argQueue.length;
          const arg = argQueue.pop();
          count += 1;
          const out = fn(arg);
          const processOut = (out, index) => {
            outs[index] = out;
            count -= 1;
            pollNext();
          };
          if (typeof out === 'object' && out.then) {
            out.then(out => processOut(out, index));
          } else {
            processOut(out, index);
          }
        }
      }
    };
    pollNext();
  });
}

তুলনা

// A simple async function that returns after the given delay
// and prints its value to allow us to determine the response order
const asyncFn = delay => new Promise(resolve => setTimeout(() => {
  console.log(delay);
  resolve(delay);
}, delay));

// List of arguments to the asyncFn function
const args = [30, 20, 15, 10];

// As a comparison of the different implementations, a low concurrency
// limit of 2 is used in order to highlight the performance differences.
// If a limit greater than or equal to args.length is used the results
// would be identical.

// Vanilla Promise.all/map combo
const out1 = await Promise.all(args.map(arg => asyncFn(arg)));
// prints: 10, 15, 20, 30
// total time: 30ms

// Pooled implementation
const out2 = await asyncPool(args, arg => asyncFn(arg), 2);
// prints: 20, 30, 15, 10
// total time: 40ms

// Batched implementation
const out3 = await asyncBatch(args, arg => asyncFn(arg), 2);
// prints: 20, 30, 20, 30
// total time: 45ms

console.log(out1, out2, out3); // prints: [30, 20, 15, 10] x 3

// Conclusion: Execution order and performance is different,
// but return order is still identical

উপসংহার

asyncPool() এটি সর্বোত্তম সমাধান হওয়া উচিত কারণ এটি আগের অনুরোধ শেষ হওয়ার সাথে সাথেই নতুন অনুরোধগুলি শুরু করার অনুমতি দেয়।

asyncBatch() এর বাস্তবায়ন বোঝার জন্য সহজ হিসাবে এটির তুলনা হিসাবে অন্তর্ভুক্ত করা হয়েছে, তবে এটি কার্যকরভাবে ধীর হওয়া উচিত কারণ পরবর্তী ব্যাচটি শুরু করতে একই ব্যাচের সমস্ত অনুরোধ শেষ করতে হবে।

এই দ্বন্দ্বযুক্ত উদাহরণে, অ-সীমাবদ্ধ ভ্যানিলা Promise.all()অবশ্যই দ্রুততম, অন্যরা সত্যিকারের বিশ্বের ভিড়ের দৃশ্যে আরও আকাঙ্ক্ষিত পারফর্ম করতে পারে।

হালনাগাদ

অন্যরা ইতিমধ্যে প্রস্তাবিত অ্যাসিঙ্ক পুলের পাঠাগারটি সম্ভবত আমার বাস্তবায়নের জন্য আরও ভাল বিকল্প কারণ এটি প্রায় অভিন্নরূপে কাজ করে এবং প্রতিশ্রুতি.বর্গ () এর চতুর ব্যবহারের সাথে আরও সংক্ষিপ্ত বাস্তবায়ন রয়েছে: https://github.com/rxaviers/ async- পুল / ব্লব / মাস্টার / lib / es7.js

আশা করি আমার উত্তরটি এখনও একটি শিক্ষামূলক মূল্য পরিবেশন করতে পারে।


1

এখানে স্ট্রিমিং এবং 'পি-সীমা' এর প্রাথমিক উদাহরণ রয়েছে। এটি মঙ্গো ডিবিতে এইচডি রিড স্ট্রিম প্রবাহিত করে।

const stream = require('stream');
const util = require('util');
const pLimit = require('p-limit');
const es = require('event-stream');
const streamToMongoDB = require('stream-to-mongo-db').streamToMongoDB;


const pipeline = util.promisify(stream.pipeline)

const outputDBConfig = {
    dbURL: 'yr-db-url',
    collection: 'some-collection'
};
const limit = pLimit(3);

async yrAsyncStreamingFunction(readStream) => {
        const mongoWriteStream = streamToMongoDB(outputDBConfig);
        const mapperStream = es.map((data, done) => {
                let someDataPromise = limit(() => yr_async_call_to_somewhere())

                    someDataPromise.then(
                        function handleResolve(someData) {

                            data.someData = someData;    
                            done(null, data);
                        },
                        function handleError(error) {
                            done(error)
                        }
                    );
                })

            await pipeline(
                readStream,
                JSONStream.parse('*'),
                mapperStream,
                mongoWriteStream
            );
        }

0

তাই আমি আমার কোডটির জন্য কিছু উদাহরণ দেখানোর চেষ্টা করেছি, তবে যেহেতু এটি কেবল একটি আমদানি স্ক্রিপ্টের জন্য এবং উত্পাদন কোড নয়, এনপিএম প্যাকেজ ব্যাচ-প্রতিশ্রুতিগুলি অবশ্যই আমার পক্ষে সহজতম পথ ছিল

দ্রষ্টব্য: প্রতিশ্রুতি সমর্থন করতে বা পলিফিল্ড করার জন্য রানটাইম প্রয়োজন।

এপিআই ব্যাচপ্রোমাইজস (অন্ত: ব্যাচসাইজ, অ্যারে: সংগ্রহ, আই => প্রতিশ্রুতি: আইট্রেটি) প্রতিশ্রুতি: প্রতিটি ব্যাচের পরে ইত্তেটারিকে ডাকা হবে।

ব্যবহার:

batch-promises
Easily batch promises

NOTE: Requires runtime to support Promise or to be polyfilled.

Api
batchPromises(int: batchSize, array: Collection, i => Promise: Iteratee)
The Promise: Iteratee will be called after each batch.

Use:
import batchPromises from 'batch-promises';
 
batchPromises(2, [1,2,3,4,5], i => new Promise((resolve, reject) => {
 
  // The iteratee will fire after each batch resulting in the following behaviour:
  // @ 100ms resolve items 1 and 2 (first batch of 2)
  // @ 200ms resolve items 3 and 4 (second batch of 2)
  // @ 300ms resolve remaining item 5 (last remaining batch)
  setTimeout(() => {
    resolve(i);
  }, 100);
}))
.then(results => {
  console.log(results); // [1,2,3,4,5]
});


0

আপনি যদি বাহ্যিক লাইব্রেরি ব্যবহার করতে না চান তবে পুনরাবৃত্তি উত্তর answer

downloadAll(someArrayWithData){
  var self = this;

  var tracker = function(next){
    return self.someExpensiveRequest(someArrayWithData[next])
    .then(function(){
      next++;//This updates the next in the tracker function parameter
      if(next < someArrayWithData.length){//Did I finish processing all my data?
        return tracker(next);//Go to the next promise
      }
    });
  }

  return tracker(0); 
}

0

Promise.raceএখানে আমার কোডের ভিতরে আমি এটি ব্যবহার করেছি

const identifyTransactions = async function() {
  let promises = []
  let concurrency = 0
  for (let tx of this.transactions) {
    if (concurrency > 4)
      await Promise.race(promises).then(r => { promises = []; concurrency = 0 })
    promises.push(tx.identifyTransaction())
    concurrency++
  }
  if (promises.length > 0)
    await Promise.race(promises) //resolve the rest
}

আপনি যদি একটি উদাহরণ দেখতে চান: https://jsfiddle.net/thecodermarcelo/av2tp83o/5/


4
আমি এই সমঝোতা কল করব না ... এটি ব্যাচের মৃত্যুদন্ড কার্যকর করার মতো ... আপনি 4 টি কাজ করেন, সবার সমাপ্তির জন্য অপেক্ষা করেন এবং তারপরে পরবর্তী 4 করুন them যদি তাদের মধ্যে একটিরও তাড়াতাড়ি সমাধান হয়ে যায় আপনি এখনও অন্য 3 টি শেষ করার জন্য অপেক্ষা করেন , আপনার কী ব্যবহার করা উচিত তা হ'লPromise.race
অবিরাম


0
  • @ টিটুকের উত্তরটি বেশ দুর্দান্ত ছিল। এটি সম্পর্কে জানতেন না এবং ভবিষ্যতে এটির সুবিধা পাবেন।
  • আমি @ ম্যাথিউরাইডআউটের উত্তরটিও উপভোগ করেছি , তবে এটি একটি বাহ্যিক গ্রন্থাগার ব্যবহার করেছে !!

যখনই সম্ভব, আমি লাইব্রেরিতে না গিয়ে এই জাতীয় জিনিসগুলি নিজেই বিকাশ করার জন্য একটি শট দেব। আপনি প্রচুর ধারণাগুলি শিখতে শেষ করেছেন যা দেখে মনে হয়েছিল আগে ভয়ঙ্কর।

আপনারা এই প্রয়াস সম্পর্কে কী ভাবেন:
(আমি এটিকে অনেক চিন্তাভাবনা দিয়েছি এবং আমি মনে করি এটি কাজ করছে, তবে এটি না থাকলে বা মূলত কিছু ভুল আছে কিনা তা উল্লেখ করুন)

 class Pool{
        constructor(maxAsync) {
            this.maxAsync = maxAsync;
            this.asyncOperationsQueue = [];
            this.currentAsyncOperations = 0
        }

        runAnother() {
            if (this.asyncOperationsQueue.length > 0 && this.currentAsyncOperations < this.maxAsync) {
                this.currentAsyncOperations += 1;
                this.asyncOperationsQueue.pop()()
                    .then(() => { this.currentAsyncOperations -= 1; this.runAnother() }, () => { this.currentAsyncOperations -= 1; this.runAnother() })
            }
        }

        add(f){  // the argument f is a function of signature () => Promise
            this.runAnother();
            return new Promise((resolve, reject) => {
                this.asyncOperationsQueue.push(
                    () => f().then(resolve).catch(reject)
                )
            })
        }
    }

//#######################################################
//                        TESTS
//#######################################################

function dbCall(id, timeout, fail) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (fail) {
               reject(`Error for id ${id}`);
            } else {
                resolve(id);
            }
        }, timeout)
    }
    )
}


const dbQuery1 = () => dbCall(1, 5000, false);
const dbQuery2 = () => dbCall(2, 5000, false);
const dbQuery3 = () => dbCall(3, 5000, false);
const dbQuery4 = () => dbCall(4, 5000, true);
const dbQuery5 = () => dbCall(5, 5000, false);


const cappedPool = new Pool(2);

const dbQuery1Res = cappedPool.add(dbQuery1).catch(i => i).then(i => console.log(`Resolved: ${i}`))
const dbQuery2Res = cappedPool.add(dbQuery2).catch(i => i).then(i => console.log(`Resolved: ${i}`))
const dbQuery3Res = cappedPool.add(dbQuery3).catch(i => i).then(i => console.log(`Resolved: ${i}`))
const dbQuery4Res = cappedPool.add(dbQuery4).catch(i => i).then(i => console.log(`Resolved: ${i}`))
const dbQuery5Res = cappedPool.add(dbQuery5).catch(i => i).then(i => console.log(`Resolved: ${i}`))

এই পদ্ধতির স্কাল / জাভাতে থ্রেড পুলগুলির মতো একটি দুর্দান্ত এপিআই সরবরাহ করে।
পুলটির সাথে একটি উদাহরণ তৈরির পরে const cappedPool = new Pool(2), আপনি কেবল এটির সাথে প্রতিশ্রুতি দিন cappedPool.add(() => myPromise)
অবিশ্বাস্যরূপে আমাদের অবশ্যই তা নিশ্চিত করতে হবে যে প্রতিশ্রুতি অবিলম্বে শুরু হচ্ছে না এবং সেজন্য আমাদের অবশ্যই ফাংশনটির সহায়তা দিয়ে "এটি অলসভাবে সরবরাহ করতে হবে"।

সবচেয়ে গুরুত্বপূর্ণ, লক্ষ্য করুন যে পদ্ধতির ফলাফলটি add একটি প্রতিশ্রুতি যা আপনার মূল প্রতিশ্রুতির মান সহ সম্পন্ন / সমাধান করা হবে ! এটি একটি খুব স্বজ্ঞাত ব্যবহার করে তোলে।

const resultPromise = cappedPool.add( () => dbCall(...))
resultPromise
.then( actualResult => {
   // Do something with the result form the DB
  }
)

0

দুর্ভাগ্যক্রমে দেশীয় প্রতিশ্রুতি দিয়ে এটি করার কোনও উপায় নেই, সুতরাং আপনাকে সৃজনশীল হতে হবে।

এটি বাইরের কোনও লাইব্রেরি ব্যবহার না করেই আমি খুঁজে পেতে পারি দ্রুততম সংক্ষিপ্ত উপায়।

এটি একটি নতুন জাভাস্ক্রিপ্ট বৈশিষ্ট্যটি একটি ইেটরেটর নামে পরিচিত ব্যবহার করে। পুনরুক্তিকারীটি মূলত কোন আইটেমগুলি প্রক্রিয়াভুক্ত হয়েছে এবং কী কী হয়নি তার খোঁজ রাখে।

কোডটিতে এটি ব্যবহার করার জন্য, আপনি অ্যাসিঙ্ক ফাংশনগুলির একটি অ্যারে তৈরি করেন। প্রতিটি অ্যাসিঙ্ক ফাংশন পরবর্তী আইটেমটির জন্য একই পুনরাবৃত্তিকে জিজ্ঞাসা করে যা প্রক্রিয়া করা প্রয়োজন। প্রতিটি ফাংশন তার নিজস্ব আইটেমকে অবিচ্ছিন্নভাবে প্রক্রিয়াজাত করে এবং যখন সম্পন্ন হয় তখন একটি নতুনটির জন্য পুনরাবৃত্তিকে জিজ্ঞাসা করে। পুনরুক্তিকারী আইটেমগুলি শেষ হয়ে গেলে, সমস্ত ফাংশন সম্পূর্ণ হয়।

অনুপ্রেরণার জন্য @ ইন্ডলেসকে ধন্যবাদ।

var items = [
    "https://www.stackoverflow.com",
    "https://www.stackoverflow.com",
    "https://www.stackoverflow.com",
    "https://www.stackoverflow.com",
    "https://www.stackoverflow.com",
    "https://www.stackoverflow.com",
    "https://www.stackoverflow.com",
    "https://www.stackoverflow.com",
];

var concurrency = 5

Array(concurrency).fill(items.entries()).map(async (cursor) => {
    for(let [index, url] of cursor){
        console.log("getting url is ", index, url);
        // run your async task instead of this next line
        var text = await fetch(url).then(res => res.text());
        console.log("text is", text.slice(0,20));
    }
})


কেন এটি চিহ্নিত হয়ে গেল তা নিয়ে কৌতূহল। আমি যেটা নিয়ে এসেছি তার সাথে এটি খুব মিল।
ক্রিস ওয়ে

0

অনেক ভাল সমাধান। আমি @ ইন্ডলেস দ্বারা পোস্ট করা মার্জিত সমাধানটি দিয়ে শুরু করেছিলাম এবং এই সামান্য এক্সটেনশন পদ্ধতিটি দিয়ে শেষ করেছি যা কোনও বাহ্যিক লাইব্রেরি ব্যবহার করে না বা এটি ব্যাচগুলিতে চালিত হয় না (যদিও ধরে নেওয়া যায় যে আপনার কাছে এসিঙ্ক ইত্যাদি বৈশিষ্ট্য রয়েছে):

Promise.allWithLimit = async (taskList, limit = 5) => {
    const iterator = taskList.entries();
    let results = new Array(taskList.length);
    let workerThreads = new Array(limit).fill(0).map(() => 
        new Promise(async (resolve, reject) => {
            try {
                let entry = iterator.next();
                while (!entry.done) {
                    let [index, promise] = entry.value;
                    try {
                        results[index] = await promise;
                        entry = iterator.next();
                    }
                    catch (err) {
                        results[index] = err;
                    }
                }
                // No more work to do
                resolve(true); 
            }
            catch (err) {
                // This worker is dead
                reject(err);
            }
        }));

    await Promise.all(workerThreads);
    return results;
};

    Promise.allWithLimit = async (taskList, limit = 5) => {
        const iterator = taskList.entries();
        let results = new Array(taskList.length);
        let workerThreads = new Array(limit).fill(0).map(() => 
            new Promise(async (resolve, reject) => {
                try {
                    let entry = iterator.next();
                    while (!entry.done) {
                        let [index, promise] = entry.value;
                        try {
                            results[index] = await promise;
                            entry = iterator.next();
                        }
                        catch (err) {
                            results[index] = err;
                        }
                    }
                    // No more work to do
                    resolve(true); 
                }
                catch (err) {
                    // This worker is dead
                    reject(err);
                }
            }));
    
        await Promise.all(workerThreads);
        return results;
    };

    const demoTasks = new Array(10).fill(0).map((v,i) => new Promise(resolve => {
       let n = (i + 1) * 5;
       setTimeout(() => {
          console.log(`Did nothing for ${n} seconds`);
          resolve(n);
       }, n * 1000);
    }));

    var results = Promise.allWithLimit(demoTasks);

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.