คำหลักผลตอบแทนใน JavaScript คืออะไร?


238

ฉันได้ยินเกี่ยวกับคำหลัก "ผลผลิต" ใน JavaScript แต่ฉันพบเอกสารที่ไม่ดีเกี่ยวกับมัน ใครสามารถอธิบายฉัน (หรือแนะนำไซต์ที่อธิบาย) การใช้งานและสิ่งที่ใช้สำหรับ


เขาอาจหมายถึง 'Yield' bytes.com/topic/python/answers/685510-yield-keyword-usage
ant

4
มันอธิบายไว้ในMDNแต่ฉันคิดว่ามันใช้ได้กับ Firefox เท่านั้นใช่ไหม มันพกพาได้อย่างไร? มีวิธีใดในการทำเช่นนี้ใน Chrome หรือ node.js? PD: ขอโทษด้วย, Javascript v1.7 + , นั่นคือคุณสมบัติที่ต้องดูเมื่อมองหาการสนับสนุน
Trylks

1
@Trylks: เครื่องกำเนิดไฟฟ้ามีอยู่ในโหนดตั้งแต่ v0.11.2
Janus Troelsen

@JanusTroelsen อย่างไรก็ตามหลังธงเท่านั้น พวกเขาได้รับการสนับสนุนใน ioJS
Dan Pantry

คำตอบ:


86

เอกสาร MDNสวยดี IMO

ฟังก์ชั่นที่มีคำหลักผลตอบแทนเป็นเครื่องกำเนิดไฟฟ้า เมื่อคุณเรียกมันว่าพารามิเตอร์อย่างเป็นทางการของมันจะถูกผูกไว้กับข้อโต้แย้งที่เกิดขึ้นจริง แต่ร่างกายของมันจะไม่ได้รับการประเมิน แต่ generator-iterator จะถูกส่งกลับมาแทน แต่ละการเรียกไปยังเมธอดถัดไปของตัวสร้างตัวสร้างตัวดำเนินการส่งผ่านอีกครั้งผ่านอัลกอริทึมการวนซ้ำ ค่าของแต่ละขั้นตอนคือค่าที่ระบุโดยคำหลักผลตอบแทน คิดว่าผลตอบแทนเป็นตัวสร้างผลตอบแทนรุ่น generator-iterator ซึ่งแสดงขอบเขตระหว่างแต่ละการวนซ้ำของอัลกอริทึม ทุกครั้งที่คุณเรียกถัดไป () รหัสเครื่องกำเนิดไฟฟ้าจะดำเนินการต่อจากคำสั่งที่ตามมาด้วยการให้ผลตอบแทน


2
@NicolasBarbulesco มีตัวอย่างที่ชัดเจนมากหากคุณคลิกไปที่เอกสาร MDN
Matt Ball

@MattBall - ฟังก์ชั่นเป็นจาวาสคริปต์สำหรับ PI เช่นนี้เพียงพอดังนี้: ฟังก์ชั่น * PI {PI = ((Math.SQRT8;) / 9801;); } - หรือมีฟังก์ชั่นการใช้งานในจาวาสคริปต์สำหรับการคำนวณ PI หรือไม่?
dschinn1001

4
อะไรคือจุดของการอ้าง MDN ที่นี่ ฉันคิดว่าทุกคนสามารถอ่านได้ใน MDN เยี่ยมชมdavidwalsh.name/promisesเพื่อเรียนรู้เพิ่มเติมเกี่ยวกับพวกเขา
Ejaz Karim

20
สิ่งนี้ทำให้เกิดการโหวตขึ้นได้อย่างไร ~ 80 เมื่อ (ก) เป็นสำเนาของ "เอกสารที่น่าสงสารมาก" ในขณะที่ผู้ถามเรียกมันและ (ข) มันบอกว่าไม่มีประโยชน์อะไร คำตอบที่ดีกว่าด้านล่าง
www-0av-Com

4
หากมีคนขอคำอธิบายเพียงแค่คัดลอกการวางเอกสารนั้นไม่เหมาะสมโดยสิ้นเชิง การถามหมายความว่าคุณได้ค้นหาในเอกสารแล้ว แต่คุณไม่เข้าใจ
Diego

205

การตอบกลับช้าอาจเป็นไปได้ว่าทุกคนรู้ในyieldตอนนี้ แต่มีเอกสารที่ดีกว่ามาบ้าง

ปรับตัวอย่างจาก"อนาคตของ Javascript: Generators"โดย James Long สำหรับมาตรฐาน Harmony อย่างเป็นทางการ:

function * foo(x) {
    while (true) {
        x = x * 2;
        yield x;
    }
}

"เมื่อคุณเรียก foo คุณจะได้รับวัตถุของตัวสร้างซึ่งมีวิธีการต่อไป"

var g = foo(2);
g.next(); // -> 4
g.next(); // -> 8
g.next(); // -> 16

ดังนั้นyieldเป็นชนิดเช่นreturn: คุณจะได้รับสิ่งที่กลับ return xส่งกลับค่าของxแต่yield xส่งกลับฟังก์ชันซึ่งให้วิธีการวนซ้ำไปยังค่าถัดไป มีประโยชน์ถ้าคุณมีโพรซีเดอร์ที่ใช้หน่วยความจำมากที่คุณอาจต้องการขัดจังหวะระหว่างการทำซ้ำ


13
มีประโยชน์ แต่ฉันเดาว่าคุณอยู่ที่function* foo(x){นั่น
Rana Deep

9
@RanaDeep: ไวยากรณ์ฟังก์ชั่นจะขยายไปยังเพิ่มตัวเลือก *โทเค็น ไม่ว่าคุณจะต้องการมันหรือไม่นั้นขึ้นอยู่กับประเภทของอนาคตที่คุณจะกลับมา รายละเอียดมีความยาว: GvR อธิบายไว้สำหรับการใช้งานของ Pythonซึ่งการใช้งานจาวาสคริปต์เป็นแบบ ใช้function *มักจะได้รับสิทธิ แต่ในบางกรณีค่าใช้จ่ายเล็กน้อยกว่าด้วยfunction yield
บิชอป

1
@ Ajedi32 ใช่คุณพูดถูก ความกลมกลืนเป็นมาตรฐานความสัมพันธ์ระหว่างfunction *และyieldและเพิ่มข้อผิดพลาดที่ยกมา ("ข้อผิดพลาดในช่วงต้นจะเพิ่มขึ้นถ้าการแสดงออกผลผลิตหรือผลผลิต * เกิดขึ้นในฟังก์ชั่นที่ไม่ใช่เครื่องกำเนิดไฟฟ้า") แต่เดิม Javascript 1.7 การดำเนินงานใน Firefox ไม่จำเป็นต้องใช้ *อัปเดตคำตอบตาม ขอบคุณ!
อธิการ

3
@MuhammadUmer Js ในที่สุดก็กลายเป็นภาษาที่คุณสามารถใช้งานได้จริง มันเรียกว่าวิวัฒนาการ
Lukas Liesis

1
ตัวอย่างมีประโยชน์ แต่ ... ฟังก์ชันคืออะไร
Diego

66

มันง่ายจริงๆนี่คือวิธีการทำงาน

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

ให้ _process = process ();

จนกว่าคุณจะเรียกใช้_process.next ()มันจะไม่รันโค้ด2 บรรทัดแรกจากนั้นผลผลิตแรกจะหยุดการทำงานชั่วคราว ที่จะกลับมาทำงานต่อไปจนกว่าหยุดจุด ( คำหลักผลผลิต ) คุณจะต้องเรียก_process.next ()

คุณสามารถคิดว่าผลตอบแทนหลายรายการเป็นจุดพักในดีบักเกอร์ javascript ภายในฟังก์ชั่นเดียว จนกว่าคุณจะบอกให้นำทางเบรกพอยต์ต่อไปมันจะไม่ดำเนินการบล็อกรหัส ( หมายเหตุ : โดยไม่ปิดกั้นแอปพลิเคชันทั้งหมด)

แต่ในขณะที่ผลผลิตดำเนินการหยุดชั่วคราวและกลับมาทำงานมันสามารถกลับผลลัพธ์บางอย่างเช่นกัน{value: any, done: boolean} ตามฟังก์ชั่นก่อนหน้านี้เราไม่ได้ปล่อยค่าใด ๆ ถ้าเราสำรวจการส่งออกก่อนหน้านี้ก็จะแสดงเหมือนกัน{ value: undefined, done: false } มีมูลค่าไม่ได้กำหนด

ให้ขุดในคำหลักผลตอบแทน เลือกที่คุณสามารถเพิ่มการแสดงออกและการตั้งค่ากำหนดค่าตัวเลือกเริ่มต้น (ไวยากรณ์เอกสารทางการ)

[rv] = yield [expression];

expression : ค่าที่ส่งคืนจากฟังก์ชันตัวสร้าง

yield any;
yield {age: 12};

rv : ส่งคืนค่าตัวเลือกที่ส่งผ่านไปยังวิธีถัดไป () ของตัวสร้าง

เพียงคุณสามารถส่งพารามิเตอร์ไปยังกระบวนการ () ฟังก์ชั่นด้วยกลไกนี้เพื่อดำเนินการส่วนต่าง ๆ ของผลผลิต

let val = yield 99; 

_process.next(10);
now the val will be 10 

ลองใช้เลย

ประเพณี

  • การประเมินผลขี้เกียจ
  • ลำดับที่ไม่มีที่สิ้นสุด
  • กระแสควบคุมแบบอะซิงโครนัส

อ้างอิง:


54

ลดความซับซ้อน / อธิบายคำตอบของ Nick Sotiros (ซึ่งฉันคิดว่ายอดเยี่ยมมาก) ฉันคิดว่าเป็นการดีที่สุดที่จะอธิบายว่าจะเริ่มเข้ารหัสด้วยyieldวิธีใด

ในความคิดของฉันประโยชน์ที่ใหญ่ที่สุดของการใช้yieldคือมันจะกำจัดปัญหาการโทรกลับซ้อนทั้งหมดที่เราเห็นในรหัส มันยากที่จะดูว่าในตอนแรกซึ่งเป็นเหตุผลที่ฉันตัดสินใจที่จะเขียนคำตอบนี้ (สำหรับตัวเองและหวังว่าคนอื่น ๆ !)

วิธีที่มันทำคือการแนะนำแนวคิดของการร่วมตามปกติซึ่งเป็นฟังก์ชันที่สามารถหยุด / หยุดชั่วคราวจนกว่าจะได้รับสิ่งที่ต้องการ ใน JavaScript function*นี้จะแสดงโดย เพียงฟังก์ชั่นสามารถใช้function*yield

นี่คือจาวาสคริปต์ทั่วไป:

loadFromDB('query', function (err, result) {
  // Do something with the result or handle the error
})

นี่คือ clunky เพราะตอนนี้ทุกรหัสของคุณ (ซึ่งเห็นได้ชัดว่าต้องรอloadFromDBสายนี้) จะต้องอยู่ในการติดต่อกลับดูน่าเกลียดนี้ สิ่งนี้ไม่ดีด้วยเหตุผลสองสามประการ ...

  • รหัสทั้งหมดของคุณมีการย่อหน้าหนึ่งระดับ
  • คุณมีจุดจบ})ที่คุณต้องติดตามทุกที่
  • function (err, result)ศัพท์แสงพิเศษทั้งหมดนี้
  • ไม่ชัดเจนว่าคุณกำลังทำสิ่งนี้เพื่อกำหนดค่าให้กับ result

ในทางตรงกันข้ามกับyieldทั้งหมดนี้สามารถทำได้ในหนึ่งบรรทัดด้วยความช่วยเหลือของกรอบการทำงานร่วมที่ดี

function* main() {
  var result = yield loadFromDB('query')
}

ดังนั้นตอนนี้ฟังก์ชั่นหลักของคุณจะให้ผลตามที่จำเป็นเมื่อมันต้องการรอตัวแปรและสิ่งที่จะโหลด แต่ตอนนี้เพื่อที่จะเรียกใช้สิ่งนี้คุณต้องเรียกใช้ฟังก์ชั่นปกติ (ไม่ใช่ฟังก์ชัน coroutine) เฟรมเวิร์กร่วมแบบง่ายสามารถแก้ไขปัญหานี้เพื่อให้สิ่งที่คุณต้องทำคือรันสิ่งนี้:

start(main())

และเริ่มมีการกำหนด (จากคำตอบของ Nick Sotiro)

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

จะพิมพ์ "Hello World" ดังนั้นคุณสามารถเปลี่ยนฟังก์ชั่นการโทรกลับใด ๆ ให้กลายเป็นจริงได้yieldโดยเพียงแค่สร้างลายเซ็นฟังก์ชั่นเดียวกัน (โดยไม่ต้องใช้ cb) และส่งคืนfunction (cb) {}ดังนี้:

function yieldAsyncFunc(arg1, arg2) {
  return function (cb) {
    realAsyncFunc(arg1, arg2, cb)
  }
}

หวังว่าด้วยความรู้นี้คุณสามารถเขียนโค้ดที่อ่านได้ง่ายและลบได้ง่ายขึ้น !


function*เป็นเพียงการทำงานปกติโดยไม่ต้องให้ผลตอบแทนหรือไม่?
Abdul

ฉันคิดว่าคุณหมายความว่าfunction *เป็นฟังก์ชั่นที่มีผลตอบแทน มันเป็นฟังก์ชั่นพิเศษที่เรียกว่าเครื่องกำเนิดไฟฟ้า
Leander

7
สำหรับผู้ที่ใช้ไปแล้วyieldทุกที่ฉันแน่ใจว่านี่เหมาะสมกว่าการโทรกลับ แต่ฉันไม่สามารถดูได้ว่าการโทรกลับสามารถอ่านได้มากกว่าการโทรกลับ
palswim

บทความนั้นยากที่จะเข้าใจ
Martian2049

18

เพื่อให้คำตอบที่สมบูรณ์: 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)

สิ่งนี้ช่วยให้เราสามารถทำสิ่งที่ขี้ขลาดจริงๆ (ค้นหา coroutine)


16

มันใช้สำหรับเครื่องกำเนิดไฟฟ้าแบบวนซ้ำ โดยทั่วไปจะช่วยให้คุณสามารถสร้างลำดับ (อาจไม่มีที่สิ้นสุด) โดยใช้รหัสขั้นตอน ดูเอกสารของ Mozilla


6

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

4

เครื่องกำเนิดไฟฟ้าลำดับ Fibonacci ใช้คำหลักผลตอบแทน

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 

4

Yeild คำหลักในฟังก์ชั่นจาวาสคริปต์ทำให้มันกำเนิด

ตัวสร้างใน javaScript คืออะไร?

เครื่องกำเนิดไฟฟ้าเป็นฟังก์ชันที่สร้างลำดับของผลลัพธ์แทนที่จะเป็นค่าเดียวเช่นคุณสร้างชุดของค่า

เครื่องกำเนิดไฟฟ้าที่มีความหมายช่วยให้เราทำงานแบบอะซิงโครนัสกับตัวทำซ้ำช่วยเหลือตอนนี้ตัววนซ้ำแฮ็คคืออะไร จริงๆ?

การทำซ้ำหมายถึงการที่เราสามารถเข้าถึงรายการได้ครั้งละหนึ่งรายการ

iterator ช่วยให้เราเข้าถึงไอเท็มได้ครั้งละหนึ่งรายการ มันช่วยให้เราเข้าถึงรายการผ่านฟังก์ชั่นเครื่องกำเนิดไฟฟ้า

ฟังก์ชั่นเครื่องกำเนิดไฟฟ้าเป็นฟังก์ชั่นที่เราใช้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

ให้ฉัน brifly อธิบายสิ่งที่เกิดขึ้น

คุณสังเกตเห็นว่าการดำเนินการถูกหยุดชั่วคราวที่yeildคำหลักแต่ละคำและเราสามารถเข้าถึงได้ก่อนyieldด้วยความช่วยเหลือของตัววนซ้ำ.next()

นี้ซ้ำกับyieldคำหลักทั้งหมดครั้งละหนึ่งแล้วส่งกลับไม่ได้กำหนดเมื่อไม่มีyieldคำหลักที่เหลืออยู่ในคำง่ายๆที่คุณสามารถพูดyieldคำหลักเป็นจุดพักที่ฟังก์ชั่นในแต่ละครั้งหยุดชั่วคราวและดำเนินการต่อเมื่อเรียกมันโดยใช้ iterator

สำหรับกรณีของเรา: _getMeDrink.next()นี่เป็นตัวอย่างของตัววนซ้ำที่ช่วยให้เราเข้าถึงจุดพักแต่ละจุดในการทำงาน

ตัวอย่างของเครื่องกำเนิดไฟฟ้า: async/await

หากคุณเห็นการใช้งานของasync/await คุณจะเห็นgenerator functions & promisesจะใช้ในการasync/awaitทำงาน

กรุณาชี้ให้เห็นข้อเสนอแนะยินดี


3

การพึ่งพาระหว่างการเรียกใช้ javascript แบบ 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()


0

ก่อนที่คุณจะเรียนรู้เกี่ยวกับผลผลิตที่คุณต้องรู้เกี่ยวกับเครื่องกำเนิดไฟฟ้า เครื่องกำเนิดไฟฟ้าถูกสร้างขึ้นโดยใช้function*ไวยากรณ์ ฟังก์ชันตัวสร้างไม่เรียกใช้โค้ด แต่จะคืนค่าชนิดตัววนซ้ำที่เรียกว่าตัวสร้างแทน เมื่อมีการกำหนดค่าโดยใช้nextเมธอดฟังก์ชันตัวสร้างจะทำงานต่อไปจนกว่าจะเจอคีย์เวิร์ด yield การใช้yieldจะให้วัตถุที่มีค่าสองค่ากลับมาหนึ่งค่าคืออีกค่าหนึ่งทำเสร็จแล้ว (บูลีน) ค่าสามารถเป็นอาร์เรย์วัตถุ ฯลฯ


0

ตัวอย่างง่ายๆ:

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}

0

ฉันพยายามทำความเข้าใจกับคำหลักที่ให้ผลตอบแทนเช่นกัน ตามความเข้าใจปัจจุบันของฉันในตัวสร้างคำหลักที่ให้ผลผลิตทำงานได้เหมือนสวิตช์บริบทของ CPU เมื่อรันคำสั่ง yield รัฐทั้งหมด (ตัวอย่างเช่นตัวแปรโลคัล) จะถูกบันทึก

นอกจากนี้วัตถุผลลัพธ์โดยตรงจะถูกส่งกลับไปยังผู้เรียกเช่น {value: 0, Done: false} ผู้เรียกสามารถใช้วัตถุผลลัพธ์นี้เพื่อตัดสินใจว่าจะ 'ปลุก' ตัวสร้างอีกครั้งโดยการเรียก next () (การเรียก next () คือการย้ำการดำเนินการ)

อีกสิ่งที่สำคัญคือมันสามารถตั้งค่าให้กับตัวแปรท้องถิ่น ค่านี้สามารถส่งผ่านโดย 'next ()' ผู้เรียกเมื่อ 'ปลุก' เครื่องกำเนิด ตัวอย่างเช่น it.next ('valueToPass') เช่นนี้: "resultValue = yield slowQuery (1);" เช่นเดียวกับเมื่อปลุกการเรียกใช้งานครั้งถัดไปผู้เรียกสามารถแทรกผลลัพธ์การทำงานบางรายการไปยังการดำเนินการได้ (การส่งไปยังตัวแปรท้องถิ่น) ดังนั้นสำหรับการดำเนินการนี้มีสองสถานะ:

  1. บริบทที่บันทึกไว้ในการดำเนินการครั้งสุดท้าย

  2. ค่าที่ฉีดโดยทริกเกอร์การดำเนินการนี้

ดังนั้นด้วยคุณสมบัตินี้เครื่องกำเนิดไฟฟ้าสามารถเรียงลำดับการดำเนินการหลาย async ผลลัพธ์ของแบบสอบถาม async แรกจะถูกส่งไปยังแบบสอบถามที่สองโดยการตั้งค่าตัวแปรท้องถิ่น (resultValue ในตัวอย่างด้านบน) การสืบค้นแบบ async ครั้งที่สองนั้นสามารถเรียกใช้งานได้โดยการตอบแบบสอบถามแบบครั้งแรก จากนั้นเคียวรี async ที่สองสามารถตรวจสอบค่าตัวแปรโลคัลเพื่อตัดสินใจขั้นตอนถัดไปเนื่องจากตัวแปรโลคัลคือค่าที่ถูกฉีดจากการตอบกลับของเคียวรีแรก

ปัญหาของการสืบค้น async คือ:

  1. โทรกลับนรก

  2. สูญเสียบริบทจนกว่าจะผ่านเป็นพารามิเตอร์ในการติดต่อกลับ

ผลผลิตและเครื่องกำเนิดไฟฟ้าสามารถช่วยทั้ง

หากไม่มีผลผลิตและตัวสร้างการเรียงลำดับแบบสอบถาม async หลายชุดต้องใช้การเรียกกลับที่ซ้อนกันพร้อมพารามิเตอร์ตามบริบทซึ่งไม่ง่ายต่อการอ่านและบำรุงรักษา

ด้านล่างนี้เป็นตัวอย่างการสืบค้น async ที่ถูกโยงซึ่งทำงานกับ nodejs:

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+++++++++++");

ด้านล่างเป็นผลการดำเนินงาน:

+++++++++++ เริ่ม +++++++++++

แบบสอบถาม 1 0

+++++++++++ ปลาย +++++++++++

แบบสอบถาม 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+++++++++++");

ต่อไปนี้เป็นผลการทำงาน:

+++++++++++ เริ่ม +++++++++++

แบบสอบถาม 1 0

+++++++++++ ปลาย +++++++++++

แบบสอบถาม 2 1

แบบสอบถาม 4 0


0

อย่าลืมไวยากรณ์ 'x of generator' ที่เป็นประโยชน์มากเพื่อวนรอบตัวสร้าง ไม่จำเป็นต้องใช้ฟังก์ชั่นถัดไป () เลย

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);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.