मैंने जावास्क्रिप्ट में "उपज" कीवर्ड के बारे में सुना, लेकिन मुझे इसके बारे में बहुत खराब दस्तावेज मिले। क्या कोई मुझे समझा सकता है (या उस साइट की सिफारिश कर सकता है जो बताती है) इसके उपयोग और इसके लिए क्या उपयोग किया जाता है?
मैंने जावास्क्रिप्ट में "उपज" कीवर्ड के बारे में सुना, लेकिन मुझे इसके बारे में बहुत खराब दस्तावेज मिले। क्या कोई मुझे समझा सकता है (या उस साइट की सिफारिश कर सकता है जो बताती है) इसके उपयोग और इसके लिए क्या उपयोग किया जाता है?
जवाबों:
MDN दस्तावेजीकरण बहुत अच्छी, IMO है।
उपज कीवर्ड युक्त फ़ंक्शन एक जनरेटर है। जब आप इसे कहते हैं, तो इसके औपचारिक पैरामीटर वास्तविक तर्कों के लिए बाध्य होते हैं, लेकिन इसका शरीर वास्तव में मूल्यांकन नहीं करता है। इसके बजाय, एक जनरेटर-पुनरावृत्त लौटाया जाता है। जनरेटर-इट्रेटर की अगली () विधि के लिए प्रत्येक कॉल पुनरावृत्ति एल्गोरिथ्म के माध्यम से एक और पास करता है। प्रत्येक चरण का मान उपज कीवर्ड द्वारा निर्दिष्ट मूल्य है। प्रतिफल के जनरेटर-पुनरावृत्ति संस्करण के रूप में उपज के बारे में सोचो, एल्गोरिथ्म के प्रत्येक पुनरावृत्ति के बीच की सीमा का संकेत। हर बार जब आप अगला () कॉल करते हैं, तो जनरेटर कोड उपज के बाद के बयान से फिर से शुरू होता है।
देर से जवाब देना, शायद हर कोई जानता है yield
अब के , लेकिन कुछ बेहतर दस्तावेज साथ आए हैं।
जेम्स लॉन्ग द्वारा "हार्मस फ्यूचर: जेनेरेटर्स" के उदाहरण को आधिकारिक हार्मनी मानक के लिए अपनाना :
function * foo(x) {
while (true) {
x = x * 2;
yield x;
}
}
"जब आप फू कहते हैं, तो आपको एक जेनरेटर ऑब्जेक्ट वापस मिल जाता है जिसकी अगली विधि होती है।"
var g = foo(2);
g.next(); // -> 4
g.next(); // -> 8
g.next(); // -> 16
तो yield
इस तरह की तरह है return
: आप कुछ वापस मिलता है। return x
का मान लौटाता है x
, लेकिन yield x
एक फ़ंक्शन देता है, जो आपको अगले मूल्य की ओर पुनरावृति करने की विधि देता है। उपयोगी यदि आपके पास एक संभावित स्मृति गहन प्रक्रिया है जिसे आप पुनरावृत्ति के दौरान बाधित करना चाहते हैं।
function* foo(x){
वहाँ हैं
*
टोकन जोड़ने के लिए फ़ंक्शन सिंटैक्स बढ़ाया जाता है । आपको जरूरत है या नहीं, यह इस बात पर निर्भर करता है कि आप किस तरह के भविष्य में लौट रहे हैं। विस्तार लंबा है: जीवीआर इसे पायथन कार्यान्वयन के लिए समझाता है , जिस पर जावास्क्रिप्ट कार्यान्वयन मॉडलिंग किया जाता है। उपयोग function *
करना हमेशा सही होगा, हालांकि कुछ मामलों में इसके function
साथ थोड़ा अधिक उपरि है yield
।
function *
और yield
, और उद्धृत त्रुटि ( "अगर एक उपज या उपज * अभिव्यक्ति एक गैर जनरेटर समारोह में होता है एक प्रारंभिक त्रुटि उठाया है") जोड़ा गया। लेकिन, फ़ायरफ़ॉक्स में मूल जावास्क्रिप्ट 1.7 के कार्यान्वयन की आवश्यकता नहीं थी*
। तदनुसार उत्तर दिया गया। धन्यवाद!
यह वास्तव में सरल है, यह है कि यह कैसे काम करता है
yield
कीवर्ड किसी भी समय असिंक्रोनस रूप से फ़ंक्शन को रोकने और फिर से शुरू करने में मदद करता है ।यह सरल जनरेटर फ़ंक्शन लें :
function* process() {
console.log('Start process 1');
console.log('Pause process2 until call next()');
yield;
console.log('Resumed process2');
console.log('Pause process3 until call next()');
let parms = yield {age: 12};
console.log("Passed by final process next(90): " + parms);
console.log('Resumed process3');
console.log('End of the process function');
}
let _process = process ();
जब तक आप फोन _process.next () यह नहीं होते पर अमल पहले 2 लाइनों कोड की, तो पहले उपज जाएगा थामने समारोह। अगले पॉज़ पॉइंट ( उपज कीवर्ड ) तक फ़ंक्शन को फिर से शुरू करने के लिए आपको _process.next () कॉल करना होगा ।
आप सोच सकते हैं कि एक एकल फ़ंक्शन के भीतर एक जावास्क्रिप्ट डिबगर में कई उपज ब्रेकपॉइंट हैं । जब तक आप अगले ब्रेकपॉइंट को नेविगेट करने के लिए नहीं कहेंगे तब तक यह कोड ब्लॉक को निष्पादित नहीं करेगा। ( नोट : पूरे आवेदन को अवरुद्ध किए बिना)
लेकिन जब उपज इस ठहराव को पूरा करती है और व्यवहार को फिर से शुरू करती है तो यह कुछ परिणाम भी {value: any, done: boolean}
दे सकती है और पिछले फ़ंक्शन के अनुसार हम किसी भी मूल्य का उत्सर्जन नहीं करते हैं। यदि हम पिछले आउटपुट का पता लगाते हैं, तो यह अपरिभाषित{ value: undefined, done: false }
मान के साथ समान दिखाई देगा ।
उपज कीवर्ड को खोदें। वैकल्पिक रूप से आप अभिव्यक्ति जोड़ सकते हैं और एक डिफ़ॉल्ट वैकल्पिक मान असाइन कर सकते हैं । (आधिकारिक डॉक्टर वाक्य रचना)
[rv] = yield [expression];
अभिव्यक्ति : मान जनरेटर समारोह से लौटने के लिए
yield any;
yield {age: 12};
आरवी : जनरेटर के अगले () विधि के लिए पारित वैकल्पिक मूल्य लौटाता है
बस आप इस तंत्र के साथ कार्य करने के लिए पैरामीटर पारित कर सकते हैं, विभिन्न उपज भागों को निष्पादित करने के लिए।
let val = yield 99;
_process.next(10);
now the val will be 10
उपयोगों
संदर्भ:
निक सोटरोस के उत्तर पर सरलीकरण / विस्तार करना (जो मुझे लगता है कि कमाल है), मुझे लगता है कि यह वर्णन करना सबसे अच्छा है कि कोई कैसे कोडिंग शुरू करेगा yield
।
मेरी राय में, उपयोग करने का सबसे बड़ा लाभ yield
का यह है कि यह उन सभी नेस्टेड कॉलबैक समस्याओं को समाप्त कर देगा जिन्हें हम कोड में देखते हैं। यह देखना कठिन है कि पहली बार में, इसीलिए मैंने यह उत्तर लिखने का फैसला किया (अपने लिए, और उम्मीद है कि अन्य लोग भी!)।
जिस तरह से यह एक सह-दिनचर्या के विचार को पेश करने से होता है, जो एक ऐसा कार्य है जो स्वेच्छा से रोक सकता है / रोक सकता है जब तक कि उसे वह नहीं मिलता जो उसे चाहिए। जावास्क्रिप्ट में, इसके द्वारा निरूपित किया जाता है function*
। केवल function*
फ़ंक्शन का उपयोग कर सकते हैं yield
।
यहाँ कुछ विशिष्ट जावास्क्रिप्ट है:
loadFromDB('query', function (err, result) {
// Do something with the result or handle the error
})
यह क्लिंकी है क्योंकि अब आपके सभी कोड (जो स्पष्ट रूप से इस loadFromDB
कॉल की प्रतीक्षा करने की आवश्यकता है ) को इस बदसूरत दिखने वाली कॉलबैक के अंदर होना चाहिए। यह कुछ कारणों से खराब है ...
})
जिसे आपको हर जगह पर नज़र रखने की आवश्यकता हैfunction (err, result)
शब्दजाल हैresult
दूसरी ओर, इस के साथ yield
, यह सब एक सह-दिनचर्या रूपरेखा की मदद से एक पंक्ति में किया जा सकता है ।
function* main() {
var result = yield loadFromDB('query')
}
और इसलिए अब आपका मुख्य कार्य जहां आवश्यक होगा, जब उसे चर और चीजों को लोड करने के लिए इंतजार करना होगा। लेकिन अब, इसे चलाने के लिए, आपको एक सामान्य (गैर-कोराउटाइन फ़ंक्शन) कॉल करने की आवश्यकता है । एक साधारण सह-दिनचर्या ढाँचा इस समस्या को ठीक कर सकता है ताकि आपको बस इतना करना पड़े:
start(main())
और प्रारंभ परिभाषित किया गया है (निक सोत्रो के उत्तर से)
function start(routine, data) {
result = routine.next(data);
if(!result.done) {
result.value(function(err, data) {
if(err) routine.throw(err); // continue next iteration of routine with an exception
else start(routine, data); // continue next iteration of routine normally
});
}
}
और अब, आपके पास सुंदर कोड हो सकता है जो बहुत अधिक पठनीय है, हटाने में आसान है, और इंडेंट, फ़ंक्शंस आदि के साथ फ़ेडल करने की आवश्यकता नहीं है।
एक दिलचस्प अवलोकन यह है कि इस उदाहरण में, yield
वास्तव में सिर्फ एक कीवर्ड है जिसे आप कॉलबैक के साथ फ़ंक्शन से पहले रख सकते हैं।
function* main() {
console.log(yield function(cb) { cb(null, "Hello World") })
}
"हैलो वर्ल्ड" प्रिंट करेगा। तो आप वास्तव में किसी भी कॉलबैक फ़ंक्शन को yield
केवल एक ही फ़ंक्शन सिग्नेचर (cb के बिना) का उपयोग करके और वापस लौटा सकते हैं function (cb) {}
, जैसे:
function yieldAsyncFunc(arg1, arg2) {
return function (cb) {
realAsyncFunc(arg1, arg2, cb)
}
}
उम्मीद है कि इस ज्ञान के साथ आप क्लीनर, अधिक पठनीय कोड लिख सकते हैं जो हटाना आसान है !
function*
उपज के बिना एक नियमित कार्य है?
function *
एक ऐसा कार्य है जिसमें उपज होती है। यह एक विशेष फ़ंक्शन है जिसे जनरेटर कहा जाता है।
yield
हर जगह का उपयोग करते हैं , मुझे यकीन है कि यह कॉलबैक की तुलना में अधिक समझ में आता है, लेकिन मैं यह देखने में विफल रहता हूं कि कॉलबैक की तुलना में यह कैसे अधिक पठनीय है।
पूर्ण उत्तर देने के लिए: के yield
समान काम कर रहा है return
, लेकिन एक जनरेटर में।
आम तौर पर दिए गए उदाहरण के लिए, यह निम्नानुसार काम करता है:
function *squareGen(x) {
var i;
for (i = 0; i < x; i++) {
yield i*i;
}
}
var gen = squareGen(3);
console.log(gen.next().value); // prints 0
console.log(gen.next().value); // prints 1
console.log(gen.next().value); // prints 4
लेकिन उपज उपज खोजशब्द का एक दूसरा उद्देश्य भी है। इसका उपयोग जनरेटर को मान भेजने के लिए किया जा सकता है।
स्पष्ट करने के लिए, एक छोटा सा उदाहरण:
function *sendStuff() {
y = yield (0);
yield y*y;
}
var gen = sendStuff();
console.log(gen.next().value); // prints 0
console.log(gen.next(2).value); // prints 4
यह काम करता है, क्योंकि मूल्य 2
को सौंपा गया है y
, इसे जनरेटर को भेजने के बाद, यह पहली उपज पर बंद हो गया (जो वापस आ गया 0
)।
यह हमें कुछ वास्तव में कायरता सामान के लिए सक्षम बनाता है। (कोरटाइन को देखें)
इसका उपयोग इटरेटर-जनरेटर के लिए किया जाता है। मूल रूप से, यह आपको प्रक्रियात्मक कोड का उपयोग करके एक (संभावित रूप से अनंत) अनुक्रम बनाने की अनुमति देता है। मोज़िला के दस्तावेज़ देखें ।
yield
कॉलआउट नरक को समाप्त करने के लिए भी इस्तेमाल किया जा सकता है, एक coroutine ढांचे के साथ।
function start(routine, data) {
result = routine.next(data);
if(!result.done) {
result.value(function(err, data) {
if(err) routine.throw(err); // continue next iteration of routine with an exception
else start(routine, data); // continue next iteration of routine normally
});
}
}
// with nodejs as 'node --harmony'
fs = require('fs');
function read(path) {
return function(callback) { fs.readFile(path, {encoding:'utf8'}, callback); };
}
function* routine() {
text = yield read('/path/to/some/file.txt');
console.log(text);
}
// with mdn javascript 1.7
http.get = function(url) {
return function(callback) {
// make xhr request object,
// use callback(null, resonseText) on status 200,
// or callback(responseText) on status 500
};
};
function* routine() {
text = yield http.get('/path/to/some/file.txt');
console.log(text);
}
// invoked as.., on both mdn and nodejs
start(routine());
उपज कीवर्ड का उपयोग करते हुए फाइबोनैचि अनुक्रम जनरेटर।
function* fibbonaci(){
var a = -1, b = 1, c;
while(1){
c = a + b;
a = b;
b = c;
yield c;
}
}
var fibonacciGenerator = fibbonaci();
fibonacciGenerator.next().value; // 0
fibonacciGenerator.next().value; // 1
fibonacciGenerator.next().value; // 1
fibonacciGenerator.next().value; // 2
Yeild
javaScript फंक्शन में कीवर्ड इसे जनरेटर बनाता है,
जावास्क्रिप्ट में जनरेटर क्या है?
एक जनरेटर एक ऐसा फ़ंक्शन है जो एकल मान के बजाय परिणामों के अनुक्रम का उत्पादन करता है, अर्थात आप मानों की एक श्रृंखला उत्पन्न करते हैं
मतलब जनरेटर हमें पुनरावृत्तियों की मदद से अतुल्यकालिक रूप से काम करने में मदद करता है, ओह अब हैक पुनरावृत्तियों क्या हैं? वास्तव में?
Iterators मतलब है जिसके माध्यम से हम एक समय में एक आइटम का उपयोग करने में सक्षम हैं
जहां से पुनरावृत्तिकर्ता हमें एक बार में आइटम एक्सेस करने में मदद करता है? यह हमें जनरेटर कार्यों के माध्यम से वस्तुओं तक पहुंचने में मदद करता है,
जनरेटर फ़ंक्शन वे हैं जिनमें हम yeild
कीवर्ड का उपयोग करते हैं , उपज कीवर्ड हमें फ़ंक्शन को रोकने और फिर से शुरू करने में मदद करते हैं
यहाँ त्वरित उदाहरण है
function *getMeDrink() {
let question1 = yield 'soda or beer' // execution will pause here because of yield
if (question1 == 'soda') {
return 'here you get your soda'
}
if (question1 == 'beer') {
let question2 = yield 'Whats your age' // execution will pause here because of yield
if (question2 > 18) {
return "ok you are eligible for it"
} else {
return 'Shhhh!!!!'
}
}
}
let _getMeDrink = getMeDrink() // initialize it
_getMeDrink.next().value // "soda or beer"
_getMeDrink.next('beer').value // "Whats your age"
_getMeDrink.next('20').value // "ok you are eligible for it"
_getMeDrink.next().value // undefined
मुझे स्पष्ट रूप से बताएं कि क्या चल रहा है
आपने देखा कि प्रत्येक yeild
कीवर्ड पर निष्पादन रोक दिया जा रहा है और हम yield
पुनरावृत्ति की मदद से सबसे पहले पहुँच सकते हैं.next()
यह yield
एक समय में सभी खोजशब्दों को पुनरावृत्त करता है और फिर अपरिभाषित लौटता है जब yield
आपके द्वारा कहे जाने वाले सरल शब्दों में अधिक कीवर्ड शेष नहीं रह जाते हैंyield
कीवर्ड ब्रेक पॉइंट है जहां हर बार कार्य रुकता है और पुनरावृत्ति का उपयोग करके कॉल करने पर केवल फिर से शुरू करें
हमारे मामले के लिए: _getMeDrink.next()
यह इटरेटर का उदाहरण है जो हमें फ़ंक्शन में प्रत्येक ब्रेक पॉइंट तक पहुंचने में मदद कर रहा है
जनरेटर का उदाहरण:
async/await
यदि आप देखते हैं के कार्यान्वयन async/await
देखें आप होगा generator functions & promises
बनाने के लिए उपयोग किया जाता है async/await
काम
कृपया किसी भी सुझाव का स्वागत किया है
Async जावास्क्रिप्ट कॉल के बीच निर्भरता।
उपज कैसे उपयोग की जा सकती है इसका एक और अच्छा उदाहरण है।
function request(url) {
axios.get(url).then((reponse) => {
it.next(response);
})
}
function* main() {
const result1 = yield request('http://some.api.com' );
const result2 = yield request('http://some.otherapi?id=' + result1.id );
console.log('Your response is: ' + result2.value);
}
var it = main();
it.next()
इससे पहले कि आप उपज के बारे में जानें आपको जनरेटर के बारे में जानना होगा। function*
सिंटैक्स का उपयोग करके जेनरेटर बनाए जाते हैं । जेनरेटर फ़ंक्शंस कोड को निष्पादित नहीं करते हैं, बल्कि एक प्रकार का इट्रेटर लौटाते हैं जिसे जनरेटर कहा जाता है। जब next
विधि का उपयोग करके एक मान दिया जाता है , तो जनरेटर फ़ंक्शन तब तक निष्पादित होता रहता है जब तक कि यह एक उपज कीवर्ड नहीं होता है। उपयोग करने yield
से आपको दो मानों वाली एक वस्तु वापस मिल जाती है, एक है मूल्य और दूसरा किया जाता है (बूलियन)। मान एक सरणी, वस्तु आदि हो सकता है।
एक सरल उदाहरण:
const strArr = ["red", "green", "blue", "black"];
const strGen = function*() {
for(let str of strArr) {
yield str;
}
};
let gen = strGen();
for (let i = 0; i < 5; i++) {
console.log(gen.next())
}
//prints: {value: "red", done: false} -> 5 times with different colors, if you try it again as below:
console.log(gen.next());
//prints: {value: undefined, done: true}
मैं उपज कीवर्ड को समझने की कोशिश कर रहा हूं। जनरेटर में मेरी वर्तमान समझ के आधार पर, उपज कीवर्ड सीपीयू संदर्भ-स्विच की तरह काम करता है। जब उपज स्टेटमेंट चलाया जाता है, तो सभी राज्य (उदाहरण के लिए, स्थानीय चर) सहेजे जाते हैं।
इसके अलावा, एक प्रत्यक्ष परिणाम ऑब्जेक्ट कॉलर को लौटाया जाएगा, जैसे {value: 0, किया: false}। कॉल करने वाले इस परिणाम वस्तु का उपयोग यह तय करने के लिए कर सकते हैं कि क्या जनरेटर को फिर से कॉल करके 'जगाया' जाए () (अगले को बुलाकर) निष्पादन को पुनरावृत्त करना है)।
एक और महत्वपूर्ण बात यह है कि यह एक स्थानीय चर के लिए एक मूल्य निर्धारित कर सकता है। यह मान जनरेटर द्वारा 'जागने' पर 'अगला ()' कॉलर द्वारा पारित किया जा सकता है। उदाहरण के लिए, it.next ('valueToPass'), इस तरह: "resultValue = उपज धीमे (1);" ठीक उसी तरह जब किसी अगले निष्पादन को जगाया जाता है, तो कॉलर निष्पादन के लिए कुछ रनिंग परिणाम को इंजेक्ट कर सकता है (इसे स्थानीय चर पर इंजेक्ट कर सकता है)। इस प्रकार, इस निष्पादन के लिए, दो प्रकार के राज्य हैं:
अंतिम निष्पादन में सहेजा गया संदर्भ।
इस निष्पादन के ट्रिगर द्वारा इंजेक्ट किए गए मान।
तो, इस सुविधा के साथ, जनरेटर कई async संचालन को सुलझा सकता है। पहले async क्वेरी का परिणाम स्थानीय चर सेट कर रहा है दूसरे को पारित किया जाएगा (परिणाम उपरोक्त उदाहरण में)। दूसरी async क्वेरी को केवल पहले async क्वेरी की प्रतिक्रिया से ट्रिगर किया जा सकता है। फिर दूसरा async क्वेरी अगले चरणों को तय करने के लिए स्थानीय चर मान की जांच कर सकती है क्योंकि स्थानीय चर पहले क्वेरी की प्रतिक्रिया से एक इंजेक्शन मूल्य है।
Async प्रश्नों की कठिनाइयाँ हैं:
कॉलबैक नरक
जब तक उन्हें कॉलबैक में पैरामीटर के रूप में पारित नहीं किया जाता है तब तक संदर्भ खो देते हैं।
उपज और जनरेटर दोनों पर मदद कर सकते हैं।
पैदावार और जनरेटर के बिना, कई एस्किंट क्वेरी को छाँटने के लिए संदर्भ के रूप में मापदंडों के साथ नेस्टेड कॉलबैक की आवश्यकता होती है जो पढ़ना और बनाए रखना आसान नहीं है।
नीचे जंजीर के साथ चलने वाला एक ज्वलंत प्रश्न उदाहरण है:
const axios = require('axios');
function slowQuery(url) {
axios.get(url)
.then(function (response) {
it.next(1);
})
.catch(function (error) {
it.next(0);
})
}
function* myGen(i=0) {
let queryResult = 0;
console.log("query1", queryResult);
queryResult = yield slowQuery('https://google.com');
if(queryResult == 1) {
console.log("query2", queryResult);
//change it to the correct url and run again.
queryResult = yield slowQuery('https://1111111111google.com');
}
if(queryResult == 1) {
console.log("query3", queryResult);
queryResult = yield slowQuery('https://google.com');
} else {
console.log("query4", queryResult);
queryResult = yield slowQuery('https://google.com');
}
}
console.log("+++++++++++start+++++++++++");
let it = myGen();
let result = it.next();
console.log("+++++++++++end+++++++++++");
नीचे चल रहा है परिणाम:
शुरू +++++++++++ +++++++++++
प्रश्न १
+++++++++++ अंत +++++++++++
क्वेरी 2 1
क्वेरी 4 0
नीचे दिए गए स्टेट पैटर्न उपरोक्त उदाहरण के लिए समान काम कर सकते हैं:
const axios = require('axios');
function slowQuery(url) {
axios.get(url)
.then(function (response) {
sm.next(1);
})
.catch(function (error) {
sm.next(0);
})
}
class StateMachine {
constructor () {
this.handler = handlerA;
this.next = (result = 1) => this.handler(this, result);
}
}
const handlerA = (sm, result) => {
const queryResult = result; //similar with generator injection
console.log("query1", queryResult);
slowQuery('https://google.com');
sm.handler = handlerB; //similar with yield;
};
const handlerB = (sm, result) => {
const queryResult = result; //similar with generator injection
if(queryResult == 1) {
console.log("query2", queryResult);
slowQuery('https://1111111111google.com');
}
sm.handler = handlerC; //similar with yield;
};
const handlerC = (sm, result) => {
const queryResult = result; //similar with generator injection;
if (result == 1 ) {
console.log("query3", queryResult);
slowQuery('https://google.com');
} else {
console.log("query4", queryResult);
slowQuery('https://google.com');
}
sm.handler = handlerEnd; //similar with yield;
};
const handlerEnd = (sm, result) => {};
console.log("+++++++++++start+++++++++++");
const sm = new StateMachine();
sm.next();
console.log("+++++++++++end+++++++++++");
निम्नलिखित परिणाम चल रहा है:
शुरू +++++++++++ +++++++++++
प्रश्न १
+++++++++++ अंत +++++++++++
क्वेरी 2 1
क्वेरी 4 0
जनरेटर के माध्यम से लूप के जनरेटर के बहुत सहायक 'x' को मत भूलना। अगले () फ़ंक्शन का उपयोग करने की कोई आवश्यकता नहीं है।
function* square(x){
for(i=0;i<100;i++){
x = x * 2;
yield x;
}
}
var gen = square(2);
for(x of gen){
console.log(x);
}