异步操作与promise

编程入门 行业动态 更新时间:2024-10-26 16:23:55

异步<a href=https://www.elefans.com/category/jswz/34/1770947.html style=操作与promise"/>

异步操作与promise

同步指的是一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。

异步指的是每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。

setTimeout(function cbFn(){console.log('learnInPro');
}, 1000);console.log('sync things');

setTimeout就是一个异步任务,当JS引擎顺序执行到setTimeout的时候发现他是个异步任务,则会把这个任务挂起,继续执行后面的代码。直到1000ms后,回调函数cbFn才会执行,这就是异步,在执行到setTimeout的时候,JS并不会傻呵呵的等着1000ms执行cbFn回调函数,而是继续执行了后面的代码。

知识剖析

首先js是单线程的语言,即同一时间只能做做一件事。那Js如何实现异步的,异步和单线程不是自相矛盾吗?其实,单线程和异步确实不能同时成为一个语言的特性。js选择了成为单线程的语言,所以它本身不可能是异步的,但js的宿主环境(比如浏览器,Node)是多线程的,宿主环境通过某种方式(事件驱动,下文会讲)使得js具备了异步的属性。

 浏览器的内核是多线程的,它们在内核制控下相互配合以保持同步,一个浏览器至少实现三个常驻线程:javascript引擎线程,UI渲染线程,浏览器事件触发线程。

 1.javascript引擎线程是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序。

2.UI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意 UI渲染线程与JS引擎是互斥的,当JS引擎执行时UI线程会被挂起,UI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。

3.事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeOut、也可来自浏览器内核的其他线程如鼠标点击、AJAX异步请求等,但由于JS的单线程关系所有这些事件都得排队等待JS引擎处理。

常见的异步

  • 回调函数
  • 事件监听
  • 发布/订阅模式(又称观察者模式)
  • promise

这里我们重点讲一下promise(一种异步编程的解决方案),

当我们做网络请求时,有时候会有很复杂的数据处理,以至于出现回调地狱式的代码,给后期维护造成了巨大的麻烦,所以我们期望一种更加优雅的方式来处理异步操作,在ES6中,增加了一种属性promise,它就是为此而生的,

普通的异步操作

setTimeout(() => {console.log('异步编程的回调')
},1000)

promise是一个类,所以使用前应该实例化

 new Promise((resolve,reject) => {setTimeout(() => {//成功时调用resolve// resolve('see you again')//失败时调用rejectreject('error')},1000)}).then((data) => {console.log(data)}).catch((data) => {console.log(data)})

当然,从表面上看确实是复杂了许多,但其逻辑清晰了不少,同时,传入的参数resolve,reject也是函数,当其调用时,各自有相应的方法响应,前者是then,后者是catch,由于都是函数,所以可以传入相应的参数,所以还可以这样写

new Promise((resolve,reject) => {setTimeout(() => {//成功时调用resolve// resolve('see you again')//失败时调用rejectreject('error')},1000)}).then((data) => {console.log(data)},(data) => {console.log(data)})
//then(参数,参数)

在进行promise操作后,会出现三种状态

  • pending  等待状态,请求过程
  • fulfill 满足状态,调用函数resolve
  • reject 拒绝状态,调用reject函数

 链式调用

new Promise((resolve,reject) => {setTimeout(() => {reslove()},1000)}).then(() => {console.log('第一个网络请求')console.log('第一个网络请求')console.log('第一个网络请求')console.log('第一个网络请求')console.log('第一个网络请求')console.log('第一个网络请求')return new Promise((reslove,reject) => {setTimeout(() => {resolve()},1000)})}).then(() => {console.log('第二个网络请求')console.log('第二个网络请求')console.log('第二个网络请求')console.log('第二个网络请求')console.log('第二个网络请求')console.log('第二个网络请求')return new Promise((reslove,reject) =>{setTimeout(() => {resolve()},1000)})}).then(() => {console.log('第三个网络请求')console.log('第三个网络请求')console.log('第三个网络请求')console.log('第三个网络请求')console.log('第三个网络请求')})

这也是链式编程的好处之一

链式其他的写法

<script>/*** 需求:网络请求的数据为aaa,* 第一步:封装为aaa111* 第二步:封装为aaa111222*/new Promise((resolve,reject) => {setTimeout(() => {resolve('aaa')},1000)    //模拟的异步操作}).then((data) => {console.log(data,'请求到的数据')// reject是可选参数// 更好的简写属性return Promoise.resolve(data + '111')}).then((data) => {console.log(data,'第一次处理数据')//  return new Promise((resolve) => {//    resolve(data + '222')//  })// 更更更好的简写属性return data + '222'}).then((data) => {console.log(data,'第二次处理')})</script>

仔细阅读上面的代码,reject的简写写法和resolve一样,而且reject可以通过throw抛出异常信息。

最后在补充一点,当遇到同时满足几个请求时,可以使用promise的all方法,此方法的参数要求传入一个可迭代对象

更多推荐

异步操作与promise

本文发布于:2024-03-09 08:49:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1724517.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:操作   promise

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!