Generator 函数
简介
Generator函数是ES6提供的一种异步编程解决方案,Generator函数除了状态机,还是一个遍历器对象生成函数。形式上,Generator函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号,二是,函数体内部使用yield语句,定义不同的内部状态。
function* helloWorldGenerator(){
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next()
// {value:'hello', done:false}
hw.next()
// {value:'world', done:false}
hw.next()
// {value:'ending', done:true}
hw.next()
// {value:undefined, done:true}
next 方法从上一次定下来的地方开始执行。直到下一个yield
停下。每次调用next,都会返回一个对象,对象包括value 和 done 属性。
next 中也可以传值,传的值作为上一次异步任务的返回结果。
举个栗子:
function* gen() {
let _url = 'www.baidu.com';
let y = yield fetch(_url);
console.log(y.info);
}
const data = {};
let g = gen();
function fetch(Str) {
data.info = Str.split('.')[1];
return Str.split('.')[1];
}
g.next(); // { value: 'baidu', done: false}
g.next(data) // { value: undefined, done: true} 输出 baidu
上述栗子第一次传入的2会被返回值 x + 2接收,返回 1+ 2 = 3 ; 第二次传入的3被y接收,返回3 。
有了这个概念,就可以分析ES6d 案例了。
function* fibs() {
let a = 0;
let b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
let [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5
根据定义可以知道Generator函数 可以遍历,也就是具有Iterator接口。解构赋值时,每次都会执行fibs函数,在函数未完成之前,都会循环赋值, a=b, b= a+b
,所以first 到 sixth 的值就是0 ~ 5.
Promise 函数
简介
一个Promise对象可以理解为一次需要执行的操作,这种操作可以通过链式的方式来调用和组织代码,这样的代码看起来更直观。
resolve 和 reject
resolve 方法将Promise函数的状态变更为成功,同时(只)可以传递一个参数。
reject 方法将Promise函数的状态变更为失败,同时(只)可以传递一个参数。
对于Promise函数,有3个状态:
- Fulfilled 表示成功状态,resolve 函数执行时更改成的状态。
- Rejected 表示失败状态,reject 函数执行时更改成的状态。
- Pending 表示Promise对象在被对象实例化的时候的状态。
then 和 catch
Promise函数之所以看起来很简洁,就是因为所有的链式操作都包含在then 和 catch 中。then 方法中接收2个参数 then(onFulfilled, onRejected)
。举个栗子:
function printHello (ready) {
return new Promise(function (resolve, reject) {
if (ready) {
resolve("Hello");
} else {
reject("Good bye!");
}
});
}
function printWorld () {
alert("World");
}
function printExclamation () {
alert("!");
}
printHello(true)
.then(function(message){
alert(message); // "hello"
})
.then(printWorld) // "world"
.then(printExclamation); // "!"
上面所有的then方法中执行的操作均处基于 printHello 的状态是fulfilled。
同时,then 函数中也可以有返回值,返回值会作为后续操作的参数。栗子:
printHello(true).then(function (message) {
return message;
}).then(function (message) {
return message + ' World';
}).then(function (message) {
return message + '!';
}).then(function (message) {
alert(message);
});
只会打印出 ‘Hello World !’;
catch
上面的栗子只在then方法中传入了一个参数 onFulfilled,第二个参数可以省略,也可以作为第二个参数卸载then方法中,也可以通过catch函数链接在then 方法后面。所以上面的代码如果需要加上错误处理的话,可以这样子:
printHello(true)
.then(function(message) {
return message;
})
.catch(function(err) {
console.log(err);
})
.then(function(message) {
return message + ' World';
})
.catch(function(err) {
console.log(err);
})
.then(function(message) {
return message + '!';
})
.catch(function(err) {
console.log(err);
})
.then(function(message) {
alert(message);
})
.catch(function(err) {
console.log(err);
});
这样子代码就很简洁。将异步的操作通过链式的方式变成了同步。
注: 如果用了then 和 catch , 那么他们都只能接收一个参数。
Promise.all
Promise.all 可以接收一个元素为 Promise 对象的数组作为参数,当这个数组里面所有的 Promise 对象都变为 resolve 时,该方法才会返回。栗子:
var p1 = new Promise(function (resolve) {
setTimeout(function () {
resolve("Hello");
}, 3000);
});
var p2 = new Promise(function (resolve) {
setTimeout(function () {
resolve("World");
}, 1000);
});
Promise.all([p1, p2]).then(function (result) {
console.log(result); // ["Hello", "World"]
});
虽然P2在执行比P1快,但是Promise.all 方法会按照数组里面的顺序将结果返回。所以输出是在3秒后。
Promise.race
Promise.race 和 Promise.all 很像,都接收一个数组,但是在数组中的promise对象只要有一个状态发生改变就会返回。而且只返回一次。
var p1 = new Promise(function (resolve) {
setTimeout(function () {
resolve("Hello");
}, 3000);
});
var p2 = new Promise(function (resolve) {
setTimeout(function () {
resolve("World");
}, 1000);
});
Promise.race([p1, p2]).then(function (result) {
console.log(result); // "World"
});