通常程序都是顺序执行(除声明外)。js传统上也是单线程运行的。
在异步编程上,之前的做法主要通过回调函数和事件监听,或者通过定时器来达到目的,在es6之后,引入了新的解决方案,就是promise 对象和 async await函数。
异步回调函数,比如:
document.querySelector('button').addEventListener('click',buttonCallback);
function buttonCallback(e){
console.log(e)
}
不是所有的回调函数都是异步执行的
setTimeout和setInterval
setTimeout是到时间执行一次
setInterval是每隔多少时间就执行一次
通过Worker把任务交给一个单独的线程
单独线程的缺点是,不能进行dom的操作,当一个函数依赖于另一个函数的结果,使用它还是不能解决异步,还是需要借助其他来实现;一般来说使用它进行一个耗时的运算是很好的方式,避免页面阻塞;简单记录一下worker:
Worker实例对象的事件句柄:
onerror:发生错误时
onmessage:有消息发送时
onmessageerror:消息错误时
Worker.postMessage() 向worker线程内部发送数据
Worker.terminate() 终止worker执行
简单例子:
运行结果:
在vue这样的项目中使用呢,直接使用会有路径的错误,这和项目打包有关系,需要安装一个worker-loader来解析worker,相关配置需要用到时再百度
promise对象
相当于一个容器,容器内放着一个未来要执行的操作(异步操作),给异步操作的成功或失败绑定相应的处理方法,promise对象也提供统一操作的接口方法。
promise的三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败);promise处于fulfilled或rejected状态时,也可以被称作settled状态(resolved 已定型状态)
promise的参数是一个函数,Promise构造函数调用时就会立即执行,函数有两个参数,resolve函数,将Promise函数状态改变为fulfilled状态和reject函数,将Promise函数状态改变为rejected状态,如果程序错误,那么promise状态为rejected,如下例子:
然后能看到会有一个报错信息如下:
提示未捕获,意思就是promise 状态失败了,但是错误消息没有接收单位,也就是没有catch;给他加上catch
这个Uncaught (in promise)后一般跟的是返回的异常信息,也就是catch回调中的参数,如果遇到值为undefined ,那就要看看是reject没有给错误消息,还是程序语句捕获到了undefined;
成功状态的回调then:
then可以接受两个参数,第一个fulfilled时,第二个rejected时,
resolve(),reject()不等于return,后边的语句依旧会执行
对于promise我们无法进行监听,无法取消,如果不设置回调函数,那内部发生的错误我们将无从得知;
promise的嵌套
运行结果:
p2 resolve方法返回p1,p1是一个Promise,所以p2自己的状态无效了,此时p2的状态取决于p1的状态;
Promise.prototype.then()
有一个返回值,一个新的promise对象,因此可以使用链式写法,比如:
Promise.prototype.catch()
返回的也是一个新的promise对象,所以catch后还可以进行.then的操作
.then(null, rejection)或.then(undefined, rejection)的别名,具有‘冒泡’性质
按照我们想要的结果是直接在catch中捕获到reject的传递的值,但在第二个then中的第二个失败回调中先捕获到了;这是promise对象状态改变后,对于then会先进行验证,一层一层往下,直到遇到接受失败状态的回调,否则就抛出错误,因此在then最好不要定义第二个失败回调,而是总是使用catch
Promise.prototype.finally()
回调函数不接受任何参数,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数
Promise.all()
返回一个新的promise对象,接受一个数组作为参数,常被用于处理多个promise对象的状态集合,所有的promise对象都成功的时候才会触发成功,所有promise返回值的数组作为成功回调的返回值,顺序和传入的promise一致:
一旦有任何一个传入promise对象失败则立即触发该promise对象的失败:
如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,会先触发自身catch,不会触发Promise.all()的catch方法。
Promise.race()
同样是将多个 Promise 实例,包装成一个新的 Promise 实例;当参数里的任意一个子promise状态变为成功或失败后,父promise马上会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应回调:
promise1状态先改变,那promise.race 状态也就跟着改变
async 异步函数
Generator 函数的语法糖。语法上来说,函数的星号(*)替换成async,yield替换成await,Generator 的执行需要手动调用next方法,或者使用co模块(一个让Generator 自动执行的小工具),async函数自带内置执行器。
co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象;await后可以跟Promise 对象和原始类型的值,对于原始类型的值,会自动转成立即 resolved 的 Promise 对象。
async 异步函数会返回一个promise对象,简单例子:
执行函数,遇到await等待执行结束,再继续执行下一个