生成器(Generator)、迭代器(Iterator)和Promise

生成器

定义形式

函数定义function直接后直接增*(星号),函数内部使用yield,yield每次返回一个值

迭代器:生成器函数和普通函数很不一样,直接调用形成迭代器

function* conso()
		{
			yield 1
			yield 2
			yield 3
			yield 4
			yield 5
		}
复制代码

既然和普通函数不一样,那如何得到生成器的值呢?for-of循环就来了
此时循环的是迭代器!!!因为直接调用了!

// 此时循环迭代器
for (let val of conso()) {
	console.log(val)
}
// 结果打印
/*
1
2
3
4
5
*/
复制代码

生成器现在可以获取值了,那迭代器呢?可以使用while循环
迭代器返回对象包含2个值,“{value, done}“`如果不可进行迭代,done值就是true,因此可利用done值进行循环

var diedaiqi = conso()
var diedaiqi = conso()
  while(!((item = diedaiqi.next()).done)) {
    console.log(item.value, item)
}
/*
1 {value: 1, done: false}
2 {value: 2, done: false}
3 {value: 3, done: false}
4 {value: 4, done: false}
5 {value: 5, done: false}
*/
复制代码

让渡生成器

看下面打印什么?

在迭代器上使用yield*操作符,程序会跳转到另外一个生成器上执行。

function* firstGenerator()
		{
			yield 'first-name'
			yield* secondGenerator() // 此时在迭代器使用yield *,会跳转到下面的生成器执行
			yield 'first-age'
		}
		function* secondGenerator()
		{
			yield 'second-name'
			yield 'second-age'
		}

		for (let gVal of firstGenerator()) {
			console.log(gVal)
		}
/*
first-name
second-name
second-age
first-age
*/
复制代码

此时又是多少呢?

function* testGenerator()
{
	let i = 0;
	while(true) {
	  yield ++i
	    }
	}

console.log(testGenerator().next().value) // 1
console.log(testGenerator().next().value) // 1
console.log(testGenerator().next().value) // 1
复制代码

和你猜测的结果是一样的,都是1。因此,如果用这种方法获取唯一ID,就要把迭代器赋值给一个变量后使用。

function* testGenerator()
		{
			let i = 0;
			while(true) {
				yield ++i
			}
		}

		let testIterator = testGenerator()
		console.log(testIterator.next().value) // 1
		console.log(testIterator.next().value) // 2
		console.log(testIterator.next().value) // 3
复制代码

生成器参数

和普通函数一样,函数定义形参,调用的时候传递实参

function* NinjaGenerator(action) {
			const imposter = yield ("Hattori " + action); 
			console.log(imposter)

			const zhy = yield ("Yoshi (" + imposter + ") " + action); 

			yield ("Yoshi (" + zhy + ") " + action); 
		}

		const ninjaIterator = NinjaGenerator("skulk");
		const result1 = ninjaIterator.next();
		console.log(result1) // {value: "Hattori skulk", done: false}
		const result2 = ninjaIterator.next("Hanzo");
		console.log(result2) // {value: "Yoshi (Hanzo) skulk", done: false}
		const result3 = ninjaIterator.next("wobuzhidao");
		console.log(result3) // {value: "Yoshi (wobuzhidao) skulk", done: false}
复制代码

解释:这个例子中我们调用了两次ninjaIterator的next方法。第一次调用
ninjaIterator.next(), 请求了生成器的第一个值。由于生成器还没开始执
行,这次调用则启动了生成器,对表达式”Hattori ” + action进行求值,
得到了值”Hattori skulk”,并将该生成器的执行挂起。这一点没什么特别
的,类似的事情我们已经做过很多次了。
然而第二次调用ninjaIterator的next方法则发生了有趣的事:
ninjaIterator.next (“Hanzo”)。这一次,我们使用next方法将计算得到的值
又传递回生成器。生成器函数耐心地等待着,在表达式yield (“Hattori “

  • action)位置挂起,故而值Hanzo作为参数传入了next()方法,并用作整

个yield表达式的值。本例中,也就是表示语句imposter = yield (“Hattori “

  • action) 中的变量imposter最终值为Hanzo。

以上展示了如何在生成器中双向通信。我们通过yield语句从生成器
中返回值,再使用迭代器的next()方法把值传回生成器。《Javascript忍者秘籍-P185》

我的理解:在next()传入参数的时候,会替换整个yield的值,但是第一次没用。。书中说是启动了生成器,第二次才起作用。依此类推…

生成器里面包含return语句的时候,后面的不在执行

function* testD()
{
	return 123;

	yield 1111;
	yield 2222;
}

var tt = testD()

while(!((item = tt.next()).done)) {
	console.log(item.value, item)
}
// 不会打印出1111和2222
复制代码

这个打印什么??

const promise = new Promise((resolve, reject) => {
resolve("Hattori");
setTimeout(()=> reject("Yoshi"), 500);
});
promise.then(val => alert("Success: " + val))
.catch(e => alert("Error: " + e));
复制代码

结果是:Success:Hattori
⚠️:走入成功函数以后,即使调用了失败回调,也没执行??为什么呢?

题2

const promise1 = new Promise((resolve, reject) => {
	resolve('123')
	reject('0000')
})
promise1.then(data => console.log(data)).catch(err => console.log(err))
// 结果:123
复制代码

题3

const promise1 = new Promise((resolve, reject) => {
	reject('0000')
	resolve('123')
})
promise1.then(data => console.log(data)).catch(err => console.log(err))
// 结果:0000
复制代码

总结:Promise里面成功和失败函数都执行的话,后一个函数不会执行(我是这么理解)!!

Promise

为了解决异步回调地狱
Promise之前的回调方式
必须全部获取到结果,才能最后执行!

var ninjas, mapInfo, plan;
$.get("data/ninjas.json", function(err, data) {
if(err) { processError(err); return; }
ninjas = data;
actionItemArrived();
});
$.get("data/mapInfo.json", function(err, data) {
if(err) { processError(err); return; }
mapInfo = data;
actionItemArrived();
});
$.get("plan.json", function(err, data) {
if(err) { processError(err); return; }
plan = data;
actionItemArrived ();
});
function actionItemArrived() {
if(ninjas != null && mapInfo != null && plan != null){
console.log("The plan is ready to be set in motion!");
}
}
function processError(err) {
alert("Error", err)
}
复制代码

拒绝Promise

显示拒绝和隐式拒绝
显式拒绝,即在一个promise的执行函数中调用传入的reject方法;
隐式拒绝,正处理一个promise的过程中抛出了一个异常。

一个Promise请求实例

function getJson(url) {
	return new Promise((resolve, reject) => {
		let xhr = new XMLHttpRequest()
		xhr.open('GET', url)
		xhr.onload = () => {
			try {
				if (xhr.status == 200) {
					resolve(JSON.parse(xhr.response))
				} else {
					reject(xhr.status + ' failed!')
				}
			} catch(e) {
				reject(e.getMessage())
			}
		}
		xhr.onerror = () => {
			reject(xhr.status + ' failed! onerror')
		}
		xhr.send()
	})
}

getJson('http://php.test.com:8081/zhy/index.php').
then(data => console.log(data)).
then(() => getJson('http://php.test.com:8081/zhy/a.php')).
then(datas => console.log(datas)).
then(() => getJson('http://php.test.com:8081/zhy/b.php')).
then(datab => console.log(datab)).
catch(err => console.log(err))

//结果
{name: "index.php的内容", age: 23}
{name: "a.php的内容", age: 33}
{name: "我是b.php的内容啊", age: 44}
复制代码

Promise.all的应用

并行请求,所有结果都可行才能走到then成功函数,否则就是catch
捕捉异常也是捕捉第一个获取到的异常

Promise.all([getJson('http://php.test.com:8081/zhy/index.php'), getJson('http://php.test.com:8081/zhy/a.php'), getJson('http://php.test.com:8081/zhy/b.php')]).
then(results => console.log(results)).
catch(err => console.log(err))

// 结果
[{name: "index.php的内容", age: 23}
{name: "a.php的内容", age: 33}
{name: "我是b.php的内容啊", age: 44}]
复制代码

Promise.race

也是并行请求,但是只会取第一个得到的结果,后面的结果会被抛弃
捕捉异常也是如此

Promise.race([getJson('http://php.test.com:8081/zhy/index.php'), getJson('http://php.test.com:8081/zhy/a.php'), getJson('http://php.test.com:8081/zhy/b.php')]).
then(results => console.log(results)).
catch(err => console.log(22222222, err))

// 结果不一定是3个种的哪个(开放题?)
复制代码

Promise还有更多的知识,这里不在仔细说明,只单纯说下常见的用法,帮助初学者快速上手!!!

生成器和Promise结合使用

不太理解。。感觉就是利用生成器的特性在执行Promise的时候可以去回调

未来的函数async

async..await 就是和Promise和生成器的语法糖
好处就是我们可以在第二个请求的时候,使用第一个请求的结果了!

(async function() {
	const data = await getJson('http://php.test.com:8081/zhy/index.php');
	console.log(data)
	const data1 = await getJson('http://php.test.com:8081/zhy/a.php');
	console.log(data1)
})()

// 结果
{name: "index.php的内容", age: 23}
{name: "a.php的内容", age: 33}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享