promise,generator函数,async函数理解与区别
promise,generator函数和async函数是es6中的三个比较重要的新语法,都是用来<u>解决异步操作</u>为问题的,我对于它们的理解是知道使用它们,但对于它们的使用场景以及区别都没有理解到位,所以,想记录一下自己对于这三者的学习,加深自己的理解。
ES6 Promise对象
1.什么是promise
promise(首字母小写)对象指的是“Promise实例对象”
Promise首字母大写且单数形式,表示“Promise构造函数”
先通俗一点来讲:
- Promise构造函数就像是一个容器,里面保存着未来才会结束的事件(这里就是异步操作)的结果,它对外提供统一的 API,自己身上有all、reject、resolve等方法,原型上有then、catch等方法。
- promise对象,它可以获取异步操作的最终状态(成功/失败)
2.promise三种状态
- promise异步操作有三种状态:pending(进行中)-fulfilled(已成功)-rejected(已失败)
- promise 对象只有:
- 从 pending 变为 fulfilled 和从 pending 变为 rejected 的状态改变。
- 只要处于 fulfilled 和 rejected ,状态就不会再变了即 resolved(已定型)。
3.then和catch方法
const p = new Promise((resolve,reject) => {
resolve(1)
// reject(3)
}).then((value) => {
console.log(value); // 1
return value * 2
}).then((value) => {
console.log(value) // 2
}).catch((err) => {
console.log(err)
})
let p = new Promise((resolve, reject) => {
//做一些异步操作
setTimeout(() => {
console.log('执行完成');
resolve('随便什么数据');
}, 2000);
});
console.log('我执行了----')
p.then((val) => {
console.log(val)
})
//输出结果: 我执行了--- 》》》 执行完成 》》》 随便什么数据
ES6 Generator函数
1.什么是generator
Generator 函数是 ES6 提供的一种异步编程解决方案。形式上,Generator 函数是一个普通函数,但是有两个特征。
一是,function关键字与函数名之间有一个星号;
二是,函数体内部使用yield语句,定义不同的内部状态。
- Generator函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用Generator函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象(Iterator Object)。
2.调用
function* gen() {
yield 1
yield 2
return 3
yield 4
}
let g = gen();
console.log(g.next()) // {value: 1, done: false}
console.log(g.next()) // {value: 2, done: false}
console.log(g.next()) // {value: 3, done: true}
console.log(g.next()) // {value: undefined, done: true}
- 通过上面这个例子可以看出,generator函数的调用和普通函数调用没什么区别,不同点在于它调用了却不会执行函数体内的语句,需要通过next()方法才能让它执行。
- 这时我才明白为什么上文说它是一个<u>遍历器对象</u>了。其实相当于一个容器,里面装着很多状态,想要读取状态就必须通过next()方法改变读取状态的指针指向,这样就能读取相应的值和状态。
3.yield表达式
yield与return
- 都能返回紧跟在语句后面的那个表达式的值
- 遇到yield,函数暂停执行,下一次再从该位置继续向后执行,而return语句不具备位置记忆的功能。
- 一个函数里面,只能执行一个return语句,但是可以执行多次yield表达式。
- 正常函数只能返回一个值,因为只能执行一次return;Generator 函数可以返回一系列的值,因为可以有任意多个yield。
语法注意点:
1.yield表达式只能用在 Generator 函数里面
2.yield表达式如果用在另一个表达式之中,必须放在圆括号里面
3.yield表达式用作函数参数或放在赋值表达式的右边,可以不加括号。
注意:如果 return 语句后面还有 yield 表达式,那么后面的 yield 完全不生效
4.next()方法
每次调用遍历器对象的 next() 方法,就会返回一个有着 value 和 done 两个属性的对象。value 属性表示当前的内部状态的值,是 yield 表达式后面那个表达式的值;done 属性是一个布尔值,表示是否遍历结束
next()方法带参:
一般情况下,next 方法不传入参数的时候,yield 表达式的返回值是 undefined 。<u>当 next 传入参数的时候,该参数会作为上一步yield的返回值。</u>
function* gen(x) {
let y = 2 * (yield (x + 1))
let z = yield (y / 3)
return (x + y + z)
}
let a = gen(5);
console.log(a.next()) // {value: 6, done: false}
console.log(a.next()) // {value: NaN, done: false}
console.log(a.next()) // {value: NaN, done: true}
let b = gen(5);
console.log(b.next()) // {value: 6, done: false}
console.log(b.next(12)) // {value: 8, done: false}
console.log(b.next(13)) // {value: 42, done: true}
- 关于a的结果:
- yield(5+1) == 6
- y = 2undefined = NAN yield(y/3) 即NAN
- z = 5 + NaN + undefined*
- 关于b的结果:
- yield(5+1) == 6
- y = 2(12) = 24 z = yield(24/3) = 8
- z = 5 + 24 + 13 = 42
ES6 async函数
async/await是es7推出的一套关于异步的终极解决方案
1.async/await基础语法
// 定义一个异步函数(假设他是一个异步函数)
getJSON(){
return 'JSON'
}
// 在需要使用上面异步函数的函数前面,加上async声明,声明这是一个异步函数
async testAsync() {
// 在异步函数前面加上await,函数执行就会等待用await声明的异步函数执行完毕之后,在往下执行
await getJSON()
//...剩下的代码
}
还需要注意的一点就是使用async/await的时候,是无法捕获错误的,这个时候就要用到我们es5里面一个被大家遗忘了的try/catch,来进行错误的捕获:
async testAsync() {
try {
await getJSON()
} catch(err) {
console.log(err)
}
// ...剩下的代码
}
注意:
1.async函数在声明形式上和普通函数没有区别,函数声明式,函数表达式,对象方法,class方法和箭头函数等都可以声明async函数。
2.任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行。
3.async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
2.async/await
async代表的意思是异步。 async函数,返回的是一个Promise对象
await代表的意思是等待,它等的还是一个Promise
async function testAsync() {
return "hello async";
}
const result = testAsync();
console.log(result);
//输出结果:Promise{<resolved>: "hello async"}
总结
- promise让异步执行看起来更清晰明了,通过then让异步执行结果分离出来。
- async/await其实是基于Promise的。async函数其实是把promise包装了一下。使用async函数可以让代码简洁很多,不需要promise一样需要些then,不需要写匿名函数处理promise的resolve值,也不需要定义多余的data变量,还避免了嵌套代码。
- async函数就是Generator函数的语法糖。async函数的返回值是 promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。