Saya mendengar tentang kata kunci "hasil" dalam JavaScript, tetapi saya menemukan dokumentasi yang sangat buruk tentang itu. Dapatkah seseorang menjelaskan saya (atau merekomendasikan situs yang menjelaskan) penggunaannya dan untuk apa digunakan?
Saya mendengar tentang kata kunci "hasil" dalam JavaScript, tetapi saya menemukan dokumentasi yang sangat buruk tentang itu. Dapatkah seseorang menjelaskan saya (atau merekomendasikan situs yang menjelaskan) penggunaannya dan untuk apa digunakan?
Jawaban:
The Dokumentasi MDN cukup bagus, IMO.
Fungsi yang mengandung kata kunci hasil adalah generator. Ketika Anda menyebutnya, parameter formal terikat dengan argumen yang sebenarnya, tetapi tubuhnya tidak dievaluasi. Sebagai gantinya, generator-iterator dikembalikan. Setiap panggilan ke metode generator-iterator berikutnya () melakukan pass lain melalui algoritma iteratif. Nilai setiap langkah adalah nilai yang ditentukan oleh kata kunci hasil. Pikirkan hasil sebagai versi generator-iterator dari pengembalian, yang menunjukkan batas antara setiap iterasi algoritma. Setiap kali Anda memanggil next (), kode generator dilanjutkan dari pernyataan setelah hasil.
Terlambat menjawab, mungkin semua orang tahu tentang yield
sekarang, tetapi beberapa dokumentasi yang lebih baik telah datang.
Mengadaptasi contoh dari "Javascript's Future: Generators" oleh James Long untuk standar Harmony resmi:
function * foo(x) {
while (true) {
x = x * 2;
yield x;
}
}
"Ketika kamu memanggil foo, kamu mendapatkan kembali objek Generator yang memiliki metode selanjutnya."
var g = foo(2);
g.next(); // -> 4
g.next(); // -> 8
g.next(); // -> 16
Begitu yield
juga seperti return
: Anda mendapatkan sesuatu kembali. return x
mengembalikan nilai x
, tetapi yield x
mengembalikan fungsi, yang memberi Anda metode untuk beralih ke nilai berikutnya. Berguna jika Anda berpotensi menjalani prosedur intensif memori yang mungkin ingin Anda interupsi selama iterasi.
function* foo(x){
ada di sana
*
. Apakah Anda memerlukannya atau tidak, itu tergantung pada jenis masa depan yang Anda kembalikan. Detailnya panjang: GvR menjelaskannya untuk implementasi Python , di mana implementasi Javascript dimodelkan. Menggunakan function *
akan selalu benar, meskipun dalam beberapa kasus sedikit lebih mahal daripada function
dengan yield
.
function *
dan yield
, dan menambahkan kesalahan yang dikutip ("Kesalahan awal dinaikkan jika ekspresi hasil atau hasil * terjadi dalam fungsi non-generator"). Tetapi, implementasi Javascript 1.7 asli di Firefox tidak memerlukan*
. Jawaban diperbarui sesuai. Terima kasih!
Ini Sangat Sederhana, Ini cara kerjanya
yield
kata kunci hanya membantu untuk menjeda dan melanjutkan fungsi kapan saja secara tidak sinkron .Ambil fungsi generator sederhana ini :
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');
}
biarkan _process = proses ();
Sampai Anda memanggil _process.next () itu tidak akan mengeksekusi 2 baris kode pertama, maka hasil pertama akan menghentikan sementara fungsi. Untuk melanjutkan fungsi sampai titik jeda berikutnya ( menghasilkan kata kunci ) Anda perlu memanggil _process.next () .
Anda dapat berpikir banyak hasil adalah breakpoint dalam debugger javascript dalam satu fungsi. Sampai Anda memberitahu untuk menavigasi breakpoint berikutnya itu tidak akan menjalankan blok kode. ( Catatan : tanpa memblokir seluruh aplikasi)
Tetapi sementara yield melakukan jeda ini dan melanjutkan perilaku itu dapat mengembalikan beberapa hasil juga {value: any, done: boolean}
sesuai dengan fungsi sebelumnya, kami belum mengeluarkan nilai apa pun. Jika kita mengeksplorasi output sebelumnya, hasilnya akan sama { value: undefined, done: false }
dengan nilai yang tidak ditentukan .
Mari kita menggali kata kunci hasil. Secara opsional, Anda dapat menambahkan ekspresi dan menetapkan menetapkan nilai opsional default . (Sintaks dokumen resmi)
[rv] = yield [expression];
Ekspresi : Nilai untuk kembali dari fungsi generator
yield any;
yield {age: 12};
rv : Mengembalikan nilai opsional yang diteruskan ke metode generator berikutnya ()
Cukup Anda dapat melewatkan parameter ke proses () berfungsi dengan mekanisme ini, untuk menjalankan bagian hasil yang berbeda.
let val = yield 99;
_process.next(10);
now the val will be 10
Penggunaan
Referensi:
Menyederhanakan / menguraikan jawaban Nick Sotiros (yang menurut saya hebat), saya pikir lebih baik untuk menggambarkan bagaimana seseorang akan mulai mengkodekan dengan yield
.
Menurut pendapat saya, keuntungan terbesar dari menggunakan yield
adalah akan menghilangkan semua masalah panggilan balik bersarang yang kita lihat dalam kode. Sulit untuk melihat bagaimana pada awalnya, itulah sebabnya saya memutuskan untuk menulis jawaban ini (untuk diri saya sendiri, dan semoga orang lain!)
Cara melakukannya adalah dengan memperkenalkan gagasan tentang rutinitas bersama, yang merupakan fungsi yang dapat secara sukarela menghentikan / berhenti sampai mendapatkan apa yang dibutuhkannya. Dalam javascript, ini dilambangkan dengan function*
. Hanya function*
fungsi yang dapat digunakan yield
.
Inilah beberapa javascript khas:
loadFromDB('query', function (err, result) {
// Do something with the result or handle the error
})
Ini kikuk karena sekarang semua kode Anda (yang jelas perlu menunggu loadFromDB
panggilan ini ) harus berada di dalam panggilan balik yang tampak jelek ini. Ini buruk karena beberapa alasan ...
})
yang perlu Anda perhatikan di mana-manafunction (err, result)
jargon ekstra iniresult
Di sisi lain, dengan yield
, semua ini dapat dilakukan dalam satu baris dengan bantuan kerangka kerja bersama yang bagus.
function* main() {
var result = yield loadFromDB('query')
}
Dan sekarang fungsi utama Anda akan menghasilkan di mana diperlukan ketika perlu menunggu variabel dan hal-hal untuk memuat. Tetapi sekarang, untuk menjalankan ini, Anda perlu memanggil yang normal (fungsi non-coroutine). Kerangka kerja bersama sederhana dapat memperbaiki masalah ini sehingga yang harus Anda lakukan adalah menjalankan ini:
start(main())
Dan mulai didefinisikan (dari jawaban 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
});
}
}
Dan sekarang, Anda dapat memiliki kode cantik yang jauh lebih mudah dibaca, mudah dihapus, dan tidak perlu mengutak-atik indentasi, fungsi, dll.
Pengamatan yang menarik adalah bahwa dalam contoh ini, yield
sebenarnya hanya kata kunci yang dapat Anda tempatkan sebelum fungsi dengan panggilan balik.
function* main() {
console.log(yield function(cb) { cb(null, "Hello World") })
}
Akan mencetak "Hello World". Jadi Anda benar-benar dapat mengubah fungsi callback menjadi menggunakan yield
hanya dengan membuat tanda tangan fungsi yang sama (tanpa cb) dan kembali function (cb) {}
, seperti:
function yieldAsyncFunc(arg1, arg2) {
return function (cb) {
realAsyncFunc(arg1, arg2, cb)
}
}
Semoga dengan pengetahuan ini Anda dapat menulis kode yang lebih bersih dan mudah dibaca yang mudah dihapus !
function*
hanya fungsi biasa tanpa hasil?
function *
adalah fungsi yang berisi hasil. Ini adalah fungsi khusus yang disebut generator.
yield
mana-mana, saya yakin ini lebih masuk akal daripada callback, tetapi saya gagal melihat bagaimana ini lebih mudah dibaca daripada callback.
Untuk memberikan jawaban yang lengkap: yield
bekerja serupa dengan return
, tetapi dalam generator.
Adapun contoh yang umum diberikan, ini berfungsi sebagai berikut:
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
Tetapi ada juga tujuan kedua dari kata kunci hasil. Ini dapat digunakan untuk mengirim nilai ke generator.
Untuk memperjelas, contoh kecil:
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
Ini bekerja, sebagai nilai 2
ditugaskan untuk y
, dengan mengirimkan ke generator, setelah itu berhenti di hasil pertama (yang kembali 0
).
Ini memungkinkan kita untuk melakukan beberapa hal yang sangat funky. (lihat coroutine)
Ini digunakan untuk iterator-generator. Pada dasarnya, ini memungkinkan Anda untuk membuat urutan (berpotensi tak terbatas) menggunakan kode prosedural. Lihat dokumentasi Mozilla .
yield
juga dapat digunakan untuk menghilangkan panggilan balik neraka, dengan kerangka kerja 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());
Generator urutan Fibonacci menggunakan kata kunci hasil.
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
kata kunci dalam fungsi javaScript membuatnya menjadi generator,
Apa itu generator di javaScript?
Generator adalah fungsi yang menghasilkan urutan hasil alih-alih nilai tunggal, yaitu Anda menghasilkan serangkaian nilai
Arti generator membantu kita bekerja secara serempak dengan iterator bantuan, Oh sekarang apa iterator hack itu? Betulkah?
Iterator artinya kita dapat mengakses item satu per satu
dari mana iterator membantu kami mengakses item satu per satu? ini membantu kami mengakses item melalui fungsi generator,
fungsi generator adalah fungsi yang kami gunakan yeild
kata kunci, menghasilkan kata kunci membantu kita dalam menjeda dan melanjutkan eksekusi fungsi
di sini adalah contoh cepat
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
izinkan saya menjelaskan apa yang sedang terjadi
Anda melihat eksekusi sedang dijeda pada setiap yeild
kata kunci dan kami dapat mengaksesnya terlebih dahuluyield
dengan bantuan iterator.next()
ini beralih ke semua yield
kata kunci satu per satu dan kemudian kembali tidak terdefinisi ketika tidak ada lagi yield
kata kunci yang tersisa dalam kata-kata sederhana yang dapat Anda ucapkanyield
kata kunci adalah break point di mana fungsi setiap kali jeda dan hanya melanjutkan ketika menyebutnya menggunakan iterator
untuk kasus kami: _getMeDrink.next()
ini adalah contoh iterator yang membantu kami mengakses setiap fungsi break point
Contoh Generator:
async/await
jika Anda melihat implementasi async/await
Anda akan melihat generator functions & promises
digunakan untuk membuatasync/await
pekerjaan
mohon tunjukkan saran yang diterima
Ketergantungan antara panggilan javascript async.
Contoh bagus lainnya tentang bagaimana hasil dapat digunakan.
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()
Sebelum Anda belajar tentang hasil, Anda perlu tahu tentang generator. Generator dibuat menggunakan function*
sintaks. Fungsi generator tidak mengeksekusi kode melainkan mengembalikan jenis iterator yang disebut generator. Ketika nilai diberikan dengan menggunakan next
metode, fungsi generator terus mengeksekusi sampai menemukan kata kunci hasil. Menggunakan yield
memberi Anda kembali objek yang berisi dua nilai, satu adalah nilai dan yang lainnya dilakukan (boolean). Nilainya bisa berupa array, objek, dll.
Contoh sederhana:
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}
Saya juga mencoba memahami kata kunci hasil. Berdasarkan pemahaman saya saat ini, dalam generator, menghasilkan kata kunci berfungsi seperti saklar konteks-CPU. Ketika pernyataan hasil dijalankan, semua status (misalnya, variabel lokal) disimpan.
Selain itu, objek hasil langsung akan dikembalikan ke pemanggil, seperti {value: 0, done: false}. Penelepon dapat menggunakan objek hasil ini untuk memutuskan apakah akan 'membangkitkan' generator lagi dengan memanggil next () (memanggil next () adalah untuk mengulangi eksekusi).
Hal penting lainnya adalah ia dapat menetapkan nilai ke variabel lokal. Nilai ini dapat dilewati oleh pemanggil 'next ()' saat 'membangunkan' generator. misalnya, it.next ('valueToPass'), seperti ini: "resultValue = yield slowQuery (1);" Sama seperti ketika membangunkan eksekusi berikutnya, pemanggil dapat menyuntikkan beberapa hasil yang berjalan ke eksekusi (menyuntikkannya ke variabel lokal). Jadi, untuk eksekusi ini, ada dua jenis negara:
konteks yang disimpan dalam eksekusi terakhir.
Nilai yang disuntikkan oleh pemicu eksekusi ini.
Jadi, dengan fitur ini, generator dapat memilah beberapa operasi async. Hasil permintaan async pertama akan diteruskan ke yang kedua dengan menetapkan variabel lokal (resultValue dalam contoh di atas). Permintaan async kedua hanya dapat dipicu oleh respons permintaan async pertama. Kemudian permintaan async kedua dapat memeriksa nilai variabel lokal untuk memutuskan langkah selanjutnya karena variabel lokal adalah nilai yang disuntikkan dari respons permintaan pertama.
Kesulitan dari permintaan async adalah:
panggilan balik neraka
kehilangan konteks kecuali meneruskannya sebagai parameter dalam panggilan balik.
hasil dan generator dapat membantu keduanya.
Tanpa hasil dan generator, untuk memilah beberapa permintaan async memerlukan panggilan balik bersarang dengan parameter sebagai konteks yang tidak mudah dibaca dan dipelihara.
Di bawah ini adalah contoh permintaan async dirantai yang berjalan dengan 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+++++++++++");
Di bawah ini adalah hasil yang berjalan:
+++++++++++ mulai +++++++++++
query1 0
+++++++++++ end +++++++++++
query2 1
query4 0
Pola keadaan di bawah ini dapat melakukan hal serupa untuk contoh di atas:
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+++++++++++");
Berikut ini adalah hasil yang berjalan:
+++++++++++ mulai +++++++++++
query1 0
+++++++++++ end +++++++++++
query2 1
query4 0
jangan lupa sintaks 'x of generator' yang sangat membantu untuk loop melalui generator. Tidak perlu menggunakan fungsi next () sama sekali.
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);
}