JavaScript异步编程几种方式

602 阅读3分钟

前言

    JavaScript程序执行是单线程,既程序按顺序一步一步向下执行,后面的程序必须等前面的程序执行完毕,这样容易造成程序阻塞,浪费CPU资源,浏览器容易进入假死状态(无响应),用户体验差,这时异步编程相应而出...

一  回调函数(callback)

   回调函数是作为函数参数形式来执行的, 它是最基础的异步执行方法,让我们看一个例子,

定义三个函数,fun2利用setTimeout实现异步函数,执行结果分别是1,3,2


当我们希望输出1,2,3时,fun3输出的顺序依赖fun2时,我们可以把fun3作为fun2的回掉函数


fun2(fun3)

若后者等待前者的执行结果,采用这种方式,我们把同步操作变成了异步操作,fun2便不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行。

二 Promise

在传统的ajax请求中,当异步请求之间的数据存在依赖关系的时候,就可能产生多层的回调fun1(fun2(fun3(fun4(...)))),这样会使代码逻辑很容易造成混乱不便于阅读和后期维护。另一方面,往往错误处理的代码和正常的业务代码耦合在一起,造成代码会极其难看。为了让编程更美好,我们就需要引入promise来降低异步编程的复杂性。

它每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数,即:

fun2.then(fun3)
fun2.then(fun3).then(fun4)//可以指定多个回掉函数
fun2.then(fun3).fail(fun4)//指定发生错误时的回调函数

ES6规定,Promise对象是一个构造函数,用来生成Promise实例。Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject。它们是两个函数,由JavaScript引擎提供,不用自己部署。

resolve函数负责把promise状态从“未完成”到“完成”(Pending 到Resolved),且异步函数执行成功后把状态作为参数传递出去;reject函数把promise状态从“未完成”到“失败”

Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。then方法接收两个回掉函数作为参数,一个是Promise对象为Resolved状态时调用,另一个是为Rejected(可选)状态时调用。

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

Promise.prototype.then()

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

Promise.prototype.catch()

   Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

Promise.all()

   Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例。Promise.all方法接受一个数组作为参数,每个数组也是一个新到promise,当状态都为Resolve时,有一个为rejected,返回的promise状态就变成rejected

三 async/await

    async 会将其后的函数(函数表达式或 Lambda)的返回值封装成一个 Promise 对象,而 await 会等待这个 Promise (也可以是任意表达式)完成,并将其 resolve 的结果返回出来。

function fun1 () {  console.log('1')}
function fun2 () {  return new Promise((resolve, reject) => {    setTimeout(() => {      console.log('2')      resolve()    }, 500)  })}
function fun3 () {  console.log('3')}
async function asyncFun () {  fun1()  await fun2()  fun3()}asyncFun()