javascript语言的执行环境是单线程(singlethread),也就是说一次只能完成一个任务。如果有多个任务,则必须排队,完成上一个任务,然后执行下一个任务,依此类推。这种模式的优点是实现起来比较简单,执行环境也比较简单;但是只要耗时长,如果一个任务耗时长,后面的任务就必须排队,这样会延迟整个程序的执行。为了解决这个问题,Javascript语言将任务执行方式分为同步(Synchronous)和异步(Asynchronous)两种。同步模式:一个任务先执行,下一个任务等待上一个任务结束,再执行,程序的执行顺序与任务顺序一致,是同步的;异步模式:每个任务都有一个或多个回调函数(callback),前一个任务结束后,不执行下一个任务,而是执行回调函数,后一个任务执行时不等待前一个任务结束,所以程序的执行顺序与任务的排列顺序不一致,异步。Javascript处理异步方法的方式有以下几种:1.回调函数回调函数是作为参数传递给另一个函数,然后在那个函数执行完之后执行的函数。回调函数是异步编程最基本的方法。它的优点是简单,易于理解和部署;缺点是容易产生回调地狱。ajax('XXX1',()=>{//回调函数体ajax('XXX2',()=>{//回调函数体ajax('XXX3',()=>{//回调函数体})})})这就是所谓的回调地狱。回调地狱带来的负面影响有:代码臃肿、可读性差、可维护性差。代码复用性差。很容易滋生虫子。异常只能在回调中处理。2、在这种事件监听方式下,异步任务的执行不依赖于代码的顺序,而是依赖于事件是否发生。(1)常用方法f1.on('done',f2);上面这行代码的意思是当f1中done事件发生时,执行f2。(2)onclick方法element.onclick=function(){//处理函数}element.onclick=handler1;element.onclick=handler2;element.onclick=handler3;//只会添加handler3并执行Browser;缺点:同一个element元素绑定多个事件时,只会添加最后一个事件(3)addEvenListenerelment.addEvenListener("click",handler1,false);elment.addEvenListener("click",handler2,false);elment.addEvenListener("点击",handler3,false);该方法的第三个参数是一个布尔值:为false时表示由内向外,为true时表示由外向内。3.发布/订阅模式我们假设有一个“信号中心”。一个任务完成后,一个信号被“发布”到信号中心,其他任务可以“订阅”到信号中心。所以你知道什么时候可以开始。这称为“发布/订阅模式”(publish-subscribepattern)。首先,f2为done信号订阅信号中心jQuery。jQuery.subscribe('完成',f2);然后,f1改写如下:信号,触发f2的执行。f2执行完后,可以取消订阅(unsubscribe)jQuery.unsubscribe('done',f2);这种方式的好处:可以查看“消息中心”,知道有多少个信号存在,每个信号有多少订阅者,以便监控程序的运行。四、promise以上都是ES6之前的异步处理方式。Promises出现在ES6之后。它是一种异步编程的解决方案——比传统的解决方案(回调函数)更合理、更强大。Promise对象有以下两个特点。对象的状态不受外界影响。Promise对象表示一个异步操作,具有三种状态:pending(进行中)、fulfilled(成功)和rejected(失败)。只有异步操作的结果才能确定当前处于哪个状态,其他任何操作都不能改变这个状态。状态一旦改变,就不会再改变,随时可以得到这个结果1.基本用法(1)ES6规定Promise对象是一个构造函数,用来生成Promise实例。constpromise=newPromise((resolve,reject)=>{if(/*异步操作成功*/){resolve(success)}else{reject(error)}})Promise接收一个函数作为参数,有resolve和函数中的reject两个参数:resolve方法的作用是将Promise的pending状态变为fullfilled,在异步操作成功后调用,异步返回的结果可以作为参数传递。reject方法的作用是将Promise的pending状态变为rejected。异步操作失败后调用,可以将异步返回的结果作为参数传递。只能执行其中一个,不能同时执行,因为Promise只能维持一个状态。(2)Promise实例生成后,可以使用then方法分别指定resolved状态和rejected状态的回调函数。promise.then((success)=>{//对应上面的resolve(success)方法},(error)=>{//对应上面的reject(error)方法}//也可以这样写(推荐使用这种写法)promise.then((success)=>{//对应上面的resolve(success)方法}).catch((error)=>{//对应上面的reject(error))方法})then(onfulfilled,onrejected)方法中有两个参数,都是函数:第一个参数执行resolve()方法(即异步成功后的回调方法)第二个参数执行reject()方法(即异步失败后的回调方法)(第二个参数可选)返回一个新的Promise对象。(3)同步执行promise构造函数,异步执行then方法constpromise=newPromise((resolve,reject)=>{console.log(1)resolve()console.log(2)})promise.then(()=>{console.log(3)})console.log(4)//12432.承诺.finally()Promise.finally()用于指定无论Promise对象的最终状态如何都会执行的操作。promise.then(result=>{···}).catch(error=>{···}).finally(()=>{···});3、Promise.all()Promise.all()用于处理多个异步过程,比如需要等待多个ajax数据返回到一个页面上,然后才执行相关Logic。constp=Promise.all([p1,p2,p3]);p的状态由p1、p2、p3决定,分为两种情况。只有当p1、p2、p3的状态都满足时,p的状态才能满足。它会变得圆满。此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。只要p1、p2、p3中的一个被拒绝,p的状态就变成被拒绝,第一个被拒绝的实例的返回值就会传递给p的回调函数。4.Promse.race()Promse.race()表示比赛。Promise.race([p1,p2,p3])中无论哪个结果快速获取都会返回那个结果,不管结果本身是成功状态还是失败状态。constp=Promise.race([p1,p2,p3])在上面的代码中,只要p1、p2、p3中的一个实例先改变状态,p的状态就会随之改变。第一个改变的Promise实例的返回值被传递给p的回调函数。5.async/awaitasync/await是JavaScript提出的解决异步问题的方案。很多人称之为异步的终极解决方案。async函数是Generator函数的语法糖。与Generator相比,Async功能的改进在于以下四点:内置执行器。Generator函数的执行必须依赖执行器,而Aysnc函数有自己的执行器,调用方法和普通函数一样。更好的语义。async和await比*和yield更具语义。适用性更广。co模块同意yield命令只能跟在Thunk函数或Promise对象之后。async函数的await命令后面可以跟Promise或原始类型(Number、string、boolean,但这等同于同步)。返回值是一个Promise。async函数的返回值是一个Promise对象,比Generator函数返回的Iterator对象更方便,可以直接使用then()方法调用。1.使用规则(1)任何前面加了async的函数,执行完后都会自动返回一个Promise对象代码返回,我们还是敲了Promise对象(2)await必须在async函数中使用,不能单独使用functiontest(){letresult=awaitPromise.resolve('success')console.log(result)}test()//执行后会报错2.await在等待什么?如果等待的对象不是promise对象,则以下表达式的结果就是它正在等待的对象;如果是promise对象,await会阻塞后面的代码,等待promise对象解析,并得到resolve的值作为await表达式的运算结果。await虽然是阻塞的,但是await处于async中,async不会阻塞。所有内部块都封装在一个promise对象中并异步执行。