Generator、async/await、Promise理解

Generator、async/await、Promise剖析

  1. Generator
  2. async/await
  3. Promise

1、Generator

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。

Generator 函数是一个普通函数,但是有两个特征。一是关键字星号(function *);二是,函数体内部使用yield表达式,定义不同的内部状态。执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}
var hello = helloWorldGenerator();

上面代码定义了一个 Generator 函数helloWorldGenerator,它内部有两个yield表达式(hello和world),即该函数有三个状态:hello,world 和 return 语句(结束执行)。但是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象(Iterator对象)

调用generator对象有两个方法:

  1. 不断地调用generator对象的next()方法,next()方法会执行generator的代码,然后,每次遇到yield x;就返回一个对象{value: x, done: true/false},然后“暂停”。返回的value就是yield的返回值,done表示这个generator是否已经执行结束了。如果done为true,则value就是return的返回值,也表示这个generator对象就已经全部执行完毕,不要再继续调用next()了。
    hello .next()  // { value: 'hello', done: false }
    hello .next()  // { value: 'world', done: false }
    hello .next()  // { value: 'ending', done: true }
    hello .next()  // { value: undefined, done: true }
    
  2. 直接用for … of循环迭代generator对象,这种方式不需要我们自己判断done。
    for(var i of hello){
        console.log(i) 
    }
    // hello 
    // world 
    

2、async/await

async/await实际上是对Generator(生成器)的封装,是一个语法糖。
async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await。async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。async函数自带执行器,自动执行,无需next()

async function helloAsync() {
    return "hello async";
}
const result = helloAsync();
console.log(result);  // Promise { 'hello async' }

async函数的返回值是 Promise 对象,可以用then方法指定下一步的操作。async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

await 是个运算符,用于组成表达式,await 表达式的运算结果取决于它等的东西。
– 如果它等到的不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西。
– 如果它等到的是一个 Promise 对象,await 会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。

3、Promise

Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

Promise对象有以下两个特点。

  1. 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,然后resolve()/reject()。
const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数,它们都是可选的。

then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。

// setTimeout 来模拟异步操作
function setTime(n) {
    return new Promise(resolve => {
        setTimeout(() => resolve(n + 200), n);
    });
}
function fn1(n) {
    return takeLongTime(n);
}
function fn2(n) {
    return takeLongTime(n);
}
function fn3(n) {
    return takeLongTime(n);
}
function doneFn() {
    const time1 = 300;
    step1(time1)  // time1: 300
        .then(time2 => step2(time2)) // time2: 500
        .then(time3 => step3(time3)) // time3: 700
        .then(time4 => { // time4: 900
            // do something...
        });
}
doneFn();

总结

Generator、async/await、Promise均可以用来实现异步处理。

1、async函数的返回值是 Promise 对象,且async函数自带执行器,自动执行,无需next。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
2、Generator 函数的返回值是 Iterator对象,可以通过next或 for of遍历执行。
3、Promise 状态更加清晰,可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。Promise.then方法更加逻辑清晰,且有promise.all/promise.race都接口提供

缺点:
1、async/await 错误处理机制问题,await 的值可能报错,最好放在try catch中执行。
2、await命令只能用在async函数之中,如果用在普通函数,就会报错。
3、async 函数可以保留运行堆栈 ,暂时保存当前执行栈
4、Promise 无法取消,一旦新建它就会立即执行,无法中途取消。

你可能感兴趣的:(VUE,javascript)