promise,generator函数,async函数理解与区别

2021-05-113138
刘婉桑
web研发

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方法指定下一步的操作。
分享
点赞3
打赏
上一篇:代理工具Fiddler -调试与替换接口状态
下一篇:Git 常用操作总结