Public
Edited
Nov 26, 2022
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
i_return_after_yield_no_braces = {
let i = this || 0;
if (paused) yield i; return
while (true) yield ++i;
}
Insert cell
Insert cell
Insert cell
Insert cell
i_return_after_yield_with_braces = {
let i = this || 0;
if (paused) { // <-- note the braces used here to accommodate multiple statements that follow
yield i;
return; // <-- note the return used here to stop the flow of the function from reaching the while(true) loop
}
while (true) yield ++i;
}
Insert cell
Insert cell
Insert cell
Insert cell
i_no_return_use_else_statement = {
let i_no_return_use_else_statement = this || 0;
if (paused) {
yield i_no_return_use_else_statement;
} else {
while (true) yield ++i_no_return_use_else_statement;
}
}
Insert cell
Insert cell
Insert cell
i_will_only_show_yielded_numbers_never_returned_string = {
let i=0;
while (i<10){
yield i++;
}
return 'Observable will not show you this string value because the generator is finished (\`done\`: true) by this point';
}
Insert cell
function* i_generator_func_yields_numbers_returns_string(){
let i=0;
while (i<10){
yield i++;
}
return 'Typical iterators will never fetch this value because the generator is finished (\`done\`: true) by this point';
}
Insert cell
md`When using the spread operator, you only see the integers yielded by the generator function, you [never see the string \`return\`ed](https://stackoverflow.com/q/65871026/1175496) by the [\`i_generator_func_yields_numbers_returns_string\` generator function](#i_generator_func_yields_numbers_returns_string):

${[...i_generator_func_yields_numbers_returns_string()]}`
Insert cell
{
for (const i of i_generator_func_yields_numbers_returns_string()){
console.warn(i);
}
return md`The [\`for (const i of generator)\` loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) in this cell is finished but check your console, when this cell is executed your console logs only *integer values* \`yield\`ed by the generator, your console never logs a string \`return\`ed by the [\`i_generator_func_yields_numbers_returns_string\` generator function](#i_generator_func_yields_numbers_returns_string)`;
}
Insert cell
Insert cell
Insert cell
manually_get_returned_value_even_though_generator_is_consumed = {
const i_generator = i_generator_func_yields_numbers_returns_string();
let i_value;
// keep *manually* iterating through the generator yourself; even until you've exhausted it, and retrieved the very last value it returned...
while (i_value = i_generator.next()){
if (i_value.done) break;
}
// then return the very last value from your generator
return md`In this example, we get the \`return\`ed value **manually** with \`next()\` and **ignore the fact that the generator was finished (\`done\`: true)**...we do something with the value anyway. Here it is:

> ${i_value.value}`;
}
Insert cell
Insert cell
Insert cell
observable_block_no_yield_keyword_return_value_used = {
return 'hi';
}
Insert cell
observable_generator_has_yield_keyword_return_value_ignored = {
yield 0;
return 'hi';
}
Insert cell
md`But even though the \`return\`ed *value* is ignored, the \`return\` statement still stops teh flow of the function, ensuring a yield *after* the \`return\` would never execute:`
Insert cell
observable_generator_has_yield_keyword_return_value_ignored_subsequent_yield_never_executed = {
yield 0;
// you will never see this 'hi' value because while the line is executed, the generator is already done;
// Observable never consumes the value from a generator's return statement
return 'hi';
// you will never see this 1 value because this yield is never executed, the generator has already consumed all its values and is marked as done as of the return statement
yield 1;
}
Insert cell
Insert cell
object_yielded_by_this_generator_cell = {

let i = 0;
let next_yield_value = undefined;
let last_yield_substitute = undefined;
let last_yielded_value = undefined;
// mutability is an anti-pattern in Observable, but I'm doing it so I can display results outside the console
// mutable keyword is not about modifying in-place, but literally re-assigning
// yield_substitute_table_for_display.splice(0,yield_substitute_table_for_display.length);
const display = [];
const add_to_display = (step)=>{display.push(step && {step, next:JSON.stringify(next_yield_value), last_sub: !last_yield_substitute ? 'undefined': JSON.stringify(last_yield_substitute), next_is_last_sub:next_yield_value===last_yield_substitute, last:JSON.stringify(last_yielded_value), next_is_last: next_yield_value===last_yielded_value, this_val:this===undefined? 'undefined': JSON.stringify(this), dt: +new Date()})};
while (i < 3) {
// yielding an object so I can check for [strict equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness)
// strict equality comparison with objects check that they [refer to the same object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality#description)
next_yield_value = { i_val: ++i };
add_to_display('before yielding');

// save the result of yielding (last_yield_substitute), i.e. what Observable passes back into the .next() function
// apparently Observable passes back in *the same object that was just yielded*
last_yield_substitute = yield Promises.delay(1000, next_yield_value);
add_to_display('after yielding before storing');

// you could also/instead save the result of yielding yourself (last_yielded_value),
// but this requires storing the yielded value into an intermediate variable (next_yield_value)
last_yielded_value = next_yield_value;
add_to_display('after yielding after storing');
add_to_display();
}
mutable yield_substitute_table_for_display = display;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
md`When a one-\`return\` or one -\`yield\` statement is reactively / input re-evaluated, then they are very similar to each other, and both can access the previously evaluated value via \`this\``
Insert cell
observable_block_this_keyword_references_other_cell = {
other_cell_value_changes_on_interval;
return [other_cell_value_changes_on_interval, JSON.stringify(this)];
}
Insert cell
observable_generator_this_keyword_references_other_cell = {
other_cell_value_changes_on_interval;
yield [other_cell_value_changes_on_interval, JSON.stringify(this)];
}
Insert cell
other_cell_value_changes_on_interval = {
let i = 0;
while (i<3){
yield Promises.tick(1000, i++);
}
}
Insert cell
Insert cell
// might cause infinite recursion trying to check for object equality *within* ths generator block
// observable_generator_this_keyword_references_other_cell_check_this = {
// other_cell_value_changes_on_interval;
// // oops risks reacting to it, infinite recurison:
// // console.error(observable_generator_this_keyword_references_other_cell_check_this_store_substitute, this)
// mutable observable_generator_this_keyword_references_other_cell_check_this_store_substitute = (yield [other_cell_value_changes_on_interval, JSON.stringify(this)]);
// }
Insert cell
Insert cell
observable_generator_this_keyword_references_other_cell_check_this_simple = {
other_cell_value_changes_on_interval;
// oops risks reacting to it, infinite recurison:
// console.error(observable_generator_this_keyword_references_other_cell_check_this_store_substitute, this)
console.error(this);
console.error(yield [other_cell_value_changes_on_interval, this]);
console.error(this);
console.error('===');
}
Insert cell
viewof paused = Inputs.input(false) /* Moving this here so I can repeat the checkbox in multiple places for the user's convenience using [Inputs.bind](https://observablehq.com/@observablehq/synchronized-inputs) */
Insert cell
import { LineChart } require('@d3/line-chart')
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more