生成器
定义形式
函数定义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}
复制代码