一、ES6 Promise对象

 

const result = new Promise((resolve, reject) => {
     if (success) {
          resolve('成功');
     } else {
          reject('失败');
     }
 });
 result.then((res) => {
     console.log(res); //输出成功
 });
 result.catch((res) => {
     console.log(res); //输出失败
 });

 

常用API:

     1.resolve 返回异步操作成功的结果

     2.reject 返回异步操作失败的结果

     3.then 执行Promise状态是成功的操作

     4.catch 执行Promise状态是失败的操作

     5.finally 不管Promise状态是成功或失败都执行的操作

 

Promise.all方法简介:

const p = Promise.all([p1, p2, p3])
//顺序执行p1,p2,p3,即使p2的执行时间较短仍要等待p1执行完成
//p1,p2,p3为promise对象
p.then((result) => {
  console.log(result)      //result 是个数组,按promise的顺序依次返回结果
}).catch((error) => {
  console.log(error)
})
p的状态由p1、p2、p3决定,分成两种情况。 
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。 
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

 

 

二、ES6 Generator 函数

       Generator函数是ES6引入的新型函数,用于异步编程,跟Promise对象联合使用的话会极大降低异步编程的编写难度和阅读难度。

       Generator函数跟普通函数的写法有非常大的区别:

        一是,function关键字与函数名之间有一个星号;
        二是,函数体内部使用yield语句,定义不同的内部状态(yield在英语里的意思就是“产出”)。

        

.next(); // 返回Object {value: "a", done: false}
.next(); // 返回Object {value: "b", done: false}
.next(); // 返回Object {value: "c", done: false}
.next(); // 返回Object {value: "ending", done: false}
.next(); // 返回Object {value: "undefined", done: false}

generator函数中next()参数:

next方法参数的作用,是为上一个yield语句赋值。
由于yield永远返回undefined(执行yield语句后就阻止了 例如:let y = yield '55',y返回undefined,下一个next方法中仍然是undefined)
这时候,如果有了next方法的参数,yield就被赋了值,当下一个next方法传入值后,y就被赋予了新值。
带参数跟不带参数的区别是,带参数的情况,首先第一步就是将上一个yield语句重置为参数值,然后再照常执行剩下的语句。总之,区别就是先有一步先重置值,接下来其他全都一样。
此带参数的方法可以用在多接口并发的处理上

generator函数在vue中的应用:

  <button @click="()=>this.testM.next()">generator</button>

  mounted(){
    this.testM=this.go()     //每次调用this.go().next()都会把原先的销毁,所以需要先保存起来,会导致每次点击都只会触发第一个yield

  }

  *go() {

     while (true) {          //实现一直循环,否则当点击二次后就无法继续执行了

     console.log('Tick!');

     yield;

     console.log('Tock!');

     yield;

    }

  },

 

var ticking = true;
var go= function() {
  if (ticking)
    console.log('Tick!');
  else
    console.log('Tock!');
  ticking = !ticking;
}

相比的优点:

Generator+Promise实现完美异步

//接口异步发生,互不阻塞。时间消耗为2s。

var resolveAfter1Second = function() {
  return new Promise(resolve => {
    setTimeout(function() {
      resolve("fast");
      console.log("fast promise is done");
    }, 1000);
  });
};
var resolveAfter2Seconds = function() {
  return new Promise(resolve => {
    setTimeout(function() {
      resolve("slow");
      console.log("slow promise is done");
    }, 2000);
  });
};
function *dealData() {   
    let p1 = resolveAfter1Second(); // 请求1获取到 r1    
    let p2 = resolveAfter2Seconds(); // 请求2获取到 r2
    //此时2个延时操作已经异步执行了,会先后打出console的内容,但是操作结果resolve并没有处理(并发执行操作,减少耗时)

    let r1 = yield p1;   //resolve的结果在这处理
    let r2 = yield p2;   //resolve的结果在这处理
    

}
var gen=dealData();         //此时"fast promise is done" 和 "fast 会在1秒后输出
var a=gen.next().value;      //此时已执行一次generator函数,‘fast promise is done’已经被打出
a.then(function(res){
  console.log(res)          //打出resolve的结果'fast' ,由于操作早已经执行,这里的结果会和‘fast promise’同时打出,不存在延时
  var b=gen.next().value.then(function(res){    //此时slot 和 slow promise is done 会在fast延迟后1秒输出
  console.log(res)
  })
})

//如果想要2个接口同步顺序发生,则:(耗时3秒)
function *dealData() {
yield resolveAfter1Second();
yield resolveAfter2Seconds();
}

 

 三、async

      以上yield + Promise的写法需要我们对拿到的promise的决议进行人工处理(区分成功或失败)           //    .then()操作

      在ES7中提供了async/await帮我们省掉了这个步骤:async/await组合的出现使得异步的世界更加完美啦~~

 

//使用async对上面的genrator+promise方法的进行优化,总耗时为2s

var resolveAfter2Seconds = function() {
  return new Promise(resolve => {
    setTimeout(function() {
      resolve("slow");
      console.log("slow promise is done");
    }, 2000);
  });
};

var resolveAfter1Second = function() {
  return new Promise(resolve => {
    setTimeout(function() {
      resolve("fast");
      console.log("fast promise is done");
    }, 1000);
  });
};
var concurrentStart = async function() {
  const slow =resolveAfter2Seconds(); // starts timer immediately      
  const fast = resolveAfter1Second(); // starts timer immediately
//此时2个延时操作已经异步执行了,会先后打出console的内容,但是操作结果resolve并没有处理(并发执行操作,减少耗时)
console.log(await fast); // fast的延时操作已经执行完毕,操作结果会立刻输出
  console.log(await  slow); // slow的延时操作会慢1s
  
}
concurrentStart()

//如果想要同步顺序执行,则:
var concurrentStart = async function() {
  const slow =await resolveAfter2Seconds(); // await会阻塞下一个接口的执行
  const fast =await resolveAfter1Second(); // 等待上一个awit执行完毕
console.log(fast); // fast的延时操作已经执行完毕,操作结果会立刻输出
  console.log(slow); // slow的延时操作会慢1s
  
}

 

那么async/await的写法和yield相比孰优孰劣呢?
其实两者都有自己独到的长处

  • async/await在处理promise的层面上省略了对决议的人工处理,让代码量得以减少,语义上也更容易理解。    //async 在异步接口处理上更加简便
  • yield包容性更广泛,async只能接口promise,yield除此之外还能接收字符串、数组、对象等各种类型的数据。   //yield可以当成一个状态机使用