एक लूप दिया गया है जैसे:

for await(let line of readFileLineByLine('./long-file.txt')) {
    const interestingFacts = await processLine(line);
}

जहां readFileLineByLine एक AsyncGenerator लौटाता है, क्या यह दूसरी पंक्ति को await processLine रिटर्न से पहले या बाद में संसाधित करना शुरू कर देगा? (यह मानते हुए कि दूसरी पंक्ति processLine पूर्ण होने से पहले तैयार है)

और यदि नहीं, तो कोई इसे समानांतर कैसे करेगा? (ताकि कई पंक्तियों को एक साथ संसाधित किया जा सके)

2
mpen 13 सितंबर 2019, 10:38

2 जवाब

सबसे बढ़िया उत्तर

आपका for await लूप निम्नलिखित के लिए एक वाक्यात्मक चीनी है:

let generator = readFileLineByLine();

while (true) {
    let promise = generator.next();
    let item = await promise;

    if (item.done)
        break;

    let line = item.value;
    await processLine(line)

}

तो इसका उत्तर है हां, readLine(nextLine) तब तक शुरू नहीं होगा जब तक processLine(previousLine) पूरा नहीं हो जाता।

यदि आप चाहते हैं कि दो फ़ंक्शन एक-दूसरे पर निर्भर न हों, तो एक विकल्प readFileLineByLine को गैर-async बनाना होगा, यानी केवल yield लंबित वादे। इस जनरेटर का सामान्य रूप से उपभोग करें, प्रत्येक वादे के साथ then(processLine) संलग्न करें और उन सभी की प्रतीक्षा करें:

let promises = [];

for (let promise of readFileLineByLinePending())
    promises.push(promise.then(processLine))

await Promise.all(promises)

यहाँ एक डेमो है:

async function delay(n) {
    return new Promise(res => setTimeout(res, n))
}


async function processLine(s) {
    console.log('process BEGIN:', s)
    await delay(300);
    console.log('process END:', s)
}

async function* readFileLineByLine() {
    for (let i = 0; i < 6; i++) {
        console.log('read BEGIN', i)
        await delay(500);
        let t = await 'line' + i;
        console.log('read END', i)
        yield t;

    }
}

function* readFileLineByLinePending() {
    for (let i = 0; i < 6; i++) {
        console.log('readPending BEGIN', i)
        let t = delay(500).then(() => {
            console.log('readPending END', i);
            return 'line' + i;
        });
        yield t;

    }
}


async function main() {

    console.time('async gen')

    for await(let line of readFileLineByLine())
       await processLine(line)

    console.log('----------------------------------------')
    console.timeEnd('async gen')
    console.log('----------------------------------------')


    console.time('sync gen')

    let promises = [];

    for (let promise of readFileLineByLinePending())
        promises.push(promise.then(processLine))

    await Promise.all(promises)

    console.log('----------------------------------------')
    console.timeEnd('sync gen')
    console.log('----------------------------------------')
}

main().then(() => console.log('done'))
.as-console-wrapper {max-height:100% !important; top:0;}
3
georg 13 सितंबर 2019, 21:38

अगला पुनरावृत्ति केवल अंतिम पुनरावृत्ति पूर्ण होने के बाद ही शुरू होगा। इसे await द्वारा for लूप के अंदर आसानी से दिखाया जा सकता है:

const asyncIterable = {
  [Symbol.asyncIterator]() {
    return {
      i: 0,
      next() {
        if (this.i < 3) {
          return Promise.resolve({ value: this.i++, done: false });
        }

        return Promise.resolve({ done: true });
      }
    };
  }
};

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

(async function() {
   for await (let num of asyncIterable) {
     console.log('start ' + num);
     await delay(1000);
     console.log('end ' + num);
   }
})();

समानांतर करने के लिए, आप एक फ़ंक्शन को कॉल कर सकते हैं (लेकिन इसके हल होने की प्रतीक्षा न करें) और (नया) प्रॉमिस को एक सरणी में धकेलें, फिर सरणी पर Promise.all पर कॉल करें:

const asyncIterable = {
  [Symbol.asyncIterator]() {
    return {
      i: 0,
      next() {
        if (this.i < 3) {
          return Promise.resolve({ value: this.i++, done: false });
        }

        return Promise.resolve({ done: true });
      }
    };
  }
};

const processNum = num => new Promise(resolve => setTimeout(resolve, 1000));

(async function() {
   console.log('start');
   const proms = [];
   for await (let num of asyncIterable) {
     proms.push(processNum(num));
   }
   await Promise.all(proms);
   console.log('all done (1000ms)');
})();

(क्योंकि पुनरावर्तनीय द्वारा लौटाई गई वस्तुओं की संख्या पहले से ज्ञात नहीं है, कुछ साफ-सुथरा दिखने वाला .map दुर्भाग्य से संभव नहीं है)

4
CertainPerformance 13 सितंबर 2019, 10:55