ONFUNS 学习&生活随笔

异步解决方案Promise、Generator、Async

Promise

Promise是JavsSript异步编程解决方案,最初由社区提出来并用第三方库实现比如Q、bluebird。不过现在已经加入ES6豪华套餐,主要通过链式调用方法解决回调嵌套问题。

Pormise有三个状态pending、fulfilled、rejected,Promise 只能被决议(完成或者拒绝)一次。之后再次试图完成或拒绝的动作都会 被忽略。因此,一旦 Promise 被决议,它就是不变量,不会发生改变。

创建Promise
var p = new Promise(function (resolve,reject){
    resolve(1)
}).then(function(value){
    console.log(value) //1
}).catch(function(err){
    console.log('错误',err)
}).finally(function(){
    console.log('最终都会执行')
})
  • 1、Promise是一个构造函数,可以使用new操作符创建promise。
  • 2、构造函数Promise的参数是一个函数,这个函数有两个参数resolve和reject,它们分别是两个函数。resolve将状态pending(等待)转换为resolved(已解决),reject 将状态pending(等待)转换为rejected(已失败)。
  • 3、创建的promise对象有then、catch、finally方法。
Promise.all

包裹多个Promise实例,新的Promise对象的状态由被包裹的Promise对象的状态决定,只有被包裹的对象状态都被resolve了,那么新的Promise的状态才会resolve,否则会reject


//都是resolve状态则返回值
var p = Promise.all([Promise.resolve(1), Promise.resolve(2)])
    .then(function(res){
        console.log(res) // [1,2]
    })

//只要有一个reject状态就catch
var p = Promise.all([Promise.resolve(1), Promise.reject(2)])
    .then(function(res){
        console.log('未返回结果,直接cacth')
    }).catch(function(err){
        console.log('reject ',err)
    })
Promise.race

包裹多个Promise实例,只要包裹的的Promise对象中有一个的状态发生了改变,那么组成的这个新的Promise对象的状态就是上面那个率先改变的Promise实例的状态。


var demo = [3, 2, 1].map((value) => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(value);
            }, value * 1000);
        })
    }
)

var p = Promise.race(demo)
    .then(function(res){
        console.log(res)  // 1
    }).catch(function(err){
        console.log('reject ',err)
    })

Generator

ES6中新加入的生成器,在Promise的基础上更进一步,允许用同步的方式来描述我们的异步流程。

generator函数样例,由 * 和 yield组成

function* generator() { 
    yield 'hello' 
    yield 'world'
}

var a= generator()
a.next() // {value:"hello",done:false}
a.next() // {value:"world",done:false}
a.next() // {value:undefined,done:true}

yield* 可以在generator函数中调用generator函数

function* a(){
    yield 1
    return 2
}

function* b(){
    var value = yield* a()
    console.log(value)
}
var c = b()
c.next()  //{value: 1, done: false}
c.next() // 2

生成器有两个方法 1、return

比如上面样例执行return方法,将生成器置为终止状态,并将value值改为入参

a.return(4) {value:4,done:true}

注意:当代码块中有try finally时,return不会终止,会先执行finally代码再终止,如:

function* generator() { 
    try{
      yield 'hello' 
    } finally{
      yield 'world'
    }
}

var a= generator()
a.next()        // {value:"hello",done:false}
a.return('end') // {value:"world",done:false}
a.next()        //{value:"4",done:false}

所以实际使用中要避免finally与yield混用

2、throw 向生成器当前暂停位置抛出错误,如生成器内部没有捕获错误则状态终止

Async

async/await语法是ES7引入的generator语法糖,内置执行器,不需要调用next执行,可以自动执行函数内部代码。

async 函数返回一个 Promise 对象 如果在 async 函数中 return 一个直接量,async 会把这个直接量通过Promise.resolve() 封装成 Promise 对象; 如果 async 函数没有返回值,它会返回 Promise.resolve(undefined)

如果await后面不是一个promise对象,那跟着的表达式的运算结果就是它的结果; 如果是一个promise对象,await会阻塞后面的代码,等promise对象resolve,得到resolve的值作为await表达式的运算结果。

await会阻塞代码执行,但await在async中,async不会阻塞,它内部所有的阻塞都被封装在一个promise对象中异步执行

附上Bable编译的 async 代码,用promise模拟实现

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  try {
    var info = gen[key](arg);
    var value = info.value;
  } catch (error) {
    reject(error);
    return;
  }
  if (info.done) {
    resolve(value);
  } else {
    Promise.resolve(value).then(_next, _throw);
  }
}


function _asyncToGenerator(fn) {
  return function () {
    var self = this,
      args = arguments;
    return new Promise(function (resolve, reject) {
      var gen = fn.apply(self, args);
      function _next(value) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
      }
      function _throw(err) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
      }
      _next(undefined);
    });
  };
}