2019-09-26 | 学习笔记 | UNLOCK | 更新时间:2019-10-9 10:50

ES6中关于异步编程的解决方案

Javascript是单线程的,同一时间只能做一件事。 JS 有事件循环,主线程和任务队列,同步任务放入主线程,只有上一个任务执行完,才执行下一个任务,异步任务则放入任务队列,只有主队列的任务全部执行完才请求任务队列。 JS 是单线程,而同步很容易发生堵塞情况,因此异步就成了多数情况的选择。异步编程一直是编程人员致力解决的问题,为此诞生了许许多多的解决方案和思路。

Promise

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象,Promise对象有两个特点:不受外部影响,状态一旦确定就不在变化。
Promise 构造函数接收一个函数作为参数,改函数的两个参数为 resolve 和 reject 。由javascript引擎提供。

const promise=new Promise((resolve,reject)=>{
  if(未来事件){   //某个未来才结束的事件,通常为异步操作
    resolve(res) //将状态从pending 转为 resolve(成功),并放出参数 
  }else{
    reject(err)  //将状态从pending 转为 reject(失败),并放出参数 
  }
})

// Preomise的实例生成后,由 .then() 指定分别指定 resolve 和 reject 状态的回调函数

promise
.then((response)=>{ // resolve响应函数
  console.log(response)
})
.catch((error)=>{   // reject 响应函数
  console.log(error)
})
.finally(()=>{  // 无法读取状态,与状态无关,总会执行
  console.log('')
})

Promise 可以应用于一些异步执行的问题,如 Axios请求 return数据异步问题

Generator

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。
Generator 函数是一个普通函数,但是有两个特征,function关键字和函数名之间有一个星号,函数内部用 yield 表达式来定义不同的内部状态

function* generator(num){
  yield '推出的参数';  // yield 类似于暂停关键点,next()执行到就停
    console.log(num)
  yield 1 + 2;
  yiele num + 1;
  // return num return 会把 done 状态改为 true,之后的 yield 就不执行了
  yield* generator    // 如果 yield 身后跟着遍历器对象,就需要在添加星号
}
let gen = generator() // 函数并未执行
gen.next()            // {value:'推出的参数,done:false}

Generator 函数可以应用于解决一些状态机的问题,设置无限循环,每次执行函数都进行状态更换

例子:

function* clock() {
  while (true) {
    console.log('开!');
    yield true;         // 执行第1次将状态返回true,并暂停执行
    console.log('关!');  
    yield false;        // 执行第2次将状态返回false,并重新循环
  }
};

async

ES2017标准引入了 async 函数,使得异步操作变得更加方便。async 函数是什么?一句话,它就是 Generator 函数的语法糖

const async = async function () {   // async 将 * 替换为 async
  const f1 = await readFile('/etc/fstab');  // async 将 yield 替换为 await
  const f2 = await readFile('/etc/shells');
};

// 和普通函数一样的执行方式,但是返回 Promise 对象,可以使用then() 方法处理返回对象

async().then((value)=>{
  console.log(value)
})

如果 await语句后面的 Promise 对象变为 reject状态,那么整个 async函数都会中断执行。如果想前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个await放在try…catch结构里面,或者使用 .catch() 。这样不管这个异步操作是否成功,第二个await都会执行

async function fun(){
  try {
    await Promise.reject('出错了');
  } catch(e) {

  }
  // .catch((err)=>{  })
  return await Promise.resolve('hello world');
}

Axios关于异步导致的返回数据undefined

在Axios 中,使用的是异步请求,这就会导致一个问题,如果需要等这个请求的返回数据的函数会在 Axios未返回数据之前就执行了,就没有拿到数据,返回undefined。这就需要使用Promise或者其他异步处理

export function Power(){
  return new Promise((resolve,reject)=>{
    let hash=location.href.split('/#/')[1]
    let power=false

    axios.post('httpss://xxxxxx',{})
    .then(function(response){
      let menu=response.data.Menulist
      for(let i in menu){
        if(menu[i].url==hash){
          power=true
          break
        }
      }
      resolve(power)
    })
    .catch(function (error){
      reject(power)
    });
  })
}
ES6