✅ 作者简介:一名平凡本科大三的学生,致力于进步前端开辟本领
✨ 个人主页:前端小白在前进的主页
系列专栏 : node.js学习专栏
⭐️ 个人社区 : 个人交换社区
学习格言: ☀️ 打不倒你的会使你更强!☀️
前言
前端js学习中,让各人最惆怅的就是异步的标题,解决异步、回调地狱等标题时你必须得学会promise,对于多数前端步调员来说promise简直就是噩梦,本篇文章就是从平凡易懂的角度做为切入点,帮助各人轻松把握promise

异步编程
想要学习promise,你必须要懂得什么是异步编程!众所周知,js语言是单线程机制。所谓单线程就是按次序执行,执行完一个使命再执行下一个。但是不影响存在同步和异步的两种操作,这两种操作服务变其实都是在一条流水线上(单线程),只是这两种操作在单线程上的执行顺序不一样罢了!当js触发到异步使命时,会将异步使命交给欣赏器处置惩罚,当执行有结果时,会把异步使命的回调函数插入待处置惩罚队列的队尾!
我们平凡的去表明一下我们的异步:异步就是从主线程发射一个子线程来完成使命,每一个使命有一个或多个回调函数(callback),前一个使命竣事后,不是执行后一个使命,而是执行回调函数,后一个使命则是不等前一个使命竣事就执行,以是步调的执行顺序与使命的分列顺序是差别等的、异步的.

该图摘自于菜鸟教程中的异步编程小节,帮助各人更好的明确什么是异步!
回调函数
回调函数的定义非常简朴:一个函数被当做一个实参传入到另一个函数(外部函数),而且这个函数在外部函数内被调用,用来完成某些使命的函数。就称为回调函数
回调函数的两种写法(实现结果雷同):
- const text = () => {
- document.write('hello james')
- }
- setTimeout(text,1000)
复制代码- setTimeout(()=>{
- document.write("hello james")
- },1000)
复制代码 这段代码中的 setTimeout 就是一个斲丧时间较长的过程,它的第一个参数是个回调函数,第二个参数是毫秒数,这个函数执行之后会产生一个子线程,子线程会等候 1 秒,然后执行回调函数 "text",在文本中输出hello james
setTimeout会在子线程中等候1秒,但是主线程的运行不会受到影响!比方以下代码:
- setTimeout(()=>{
- document.write("hello davis")
- },1000)
- console.log('123456');
复制代码 在这里会先打印出来123456(主线程),然后一秒后在文本中输出hello davis(子线程)
回调地狱
回调地狱这个词听起来就非常的高大上,想要接触Promise之前,必须要懂得什么是回调地狱,以及为什么会产生回调地狱?
先来看看概念:当一个回调函数嵌套一个回调函数的时候就会出现一个嵌套结构当嵌套的多了就会出现回调地狱的情况。
举个例子:
比如我们发送三个 ajax 请求:
- 第一个正常发送
- 第二个请求必要第一个请求的结果中的某一个值作为参数
- 第三个请求必要第二个请求的结果中的某一个值作为参数
你会看到以下代码:
- $.ajax({
- url: '我是第一个请求',
- type: 'get',
- success (res) {
- // 现在发送第二个请求
- $.ajax({
- url: '我是第二个请求',
- type:'post',
- data: { a: res.a, b: res.b },
- success (res1) {
- // 进行第三个请求
- $.ajax({
- url: '我是第三个请求',
- type:'post',
- data: { a: res1.a, b: res1.b },
- success (res2) {
- console.log(res2)
- }
- })
- }
- })
- }
- })
复制代码 这种代码看起来属实是折磨人啊!当我们把代码写成如许的时候,就陷入了可维护性差的状态了,代码体验非常的不精良,看一会就给看懵了,为相识决这个标题,于是,就引入了我们的Promise,用Promise去解决回调地狱标题!
Promise
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更公道和更强盛,它是一个 ECMAScript 6 提供的类,目的是更加优雅地书写复杂的异步使命。
Promise对象有以下两个特点:
- 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(举行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“答应”,体现其他本领无法改变。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种大概:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。假如改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全差别,事件的特点是,假如你错过了它,再去监听,是得不到结果的。
两个特点摘自于阮一峰ES6文章
Promise语法格式
- new Promise(function (resolve, reject) {
- // resolve 表示成功的回调
- // reject 表示失败的回调
- }).then(function (res) {
- // 成功的函数
- }).catch(function (err) {
- // 失败的函数
- })
复制代码 出现了new关键字,就明确了Promise对象其实就是一个构造函数,是用来天生Promise实例的。能看出来构造函数吸收了一个函数作为参数,该函数就是Promise构造函数的回调函数,该函数中有两个参数resolve和reject,这两个参数也分别是两个函数!
简朴的去明确的话resolve函数的目的是将Promise对象状态酿成成功状态,在异步操作成功时调用,将异步操作的结果,作为参数通报出去。reject函数的目的是将Promise对象的状态酿成失败状态,在异步操作失败时调用,并将异步操作报出的错误,作为参数通报出去。
Promise实例天生以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
代码示例:
- const promise = new Promise((resolve,reject)=>{
- //异步代码
- setTimeout(()=>{
- // resolve(['111','222','333'])
- reject('error')
- },2000)
- })
- promise.then((res)=>{
- //兑现承诺,这个函数被执行
- console.log('success',res);
- }).catch((err)=>{
- //拒绝承诺,这个函数就会被执行
- console.log('fail',err);
- })
复制代码 代码分析:
上边说到Promise是一个构造函数,new之后便是说调用了构造函数,构造函数中传的参数是一个函数,这个函数内的两个参数分别又是两个函数(reslove和reject),固然感觉很绕,但是理清思路会很清楚的!
我们得到对象promise,promise对象中自带有两个方法then和catch,这两个方法中会分别再传入一个回调函数,这个回调函数的目的在于返回你所必要成功或失败的信息!那么怎么去调用这两个回调函数呢?
看下方图可以快速明确:

这两个函数分别做为参数(reslove和reject)传到上方的函数中去了.随后在构造函数的回调函数中写入异步代码(比方:ajax和定时器),这里使用了定时器作为例子,假如你想表达的是成功回调,你可以在内部调用函数reslove('一样平常情况下是后端返回的成功数据)。假如你想表达的是失败回调,你可以调用reject('一样平常情况下是后端返回的失败信息').
这些就是Promise执行的过程!固然明确着很绕,但是多读几遍绝对有不一样的劳绩!
Promise链式
then方法返回的是一个新的Promise实例(注意:不是原来那个Promise实例)。因此可以接纳链式写法,即then方法背面再调用另一个then方法
实际案例:
我想要实如今一个数组中查察一个帖子,但是我最终的目的是得到这个帖子下面的全部批评,这该怎么实现呢?
实现思路:
先从一个接口中获取这个帖子的信息,然后通过该帖子的帖子id从而获取到该帖子下的全部批评
代码如下:
- pajax({
- url:"http://localhost:3000/news",
- data : {
- author : "james"
- }
- }).then(res=>{
- return pajax({
- url : "http://localhost:3000/comments",
- data : {
- newsId : res[0].id
- }
- })
- }).then(res=>{
- console.log(res);
- }).catch(err=>{
- console.log(err);
- })
复制代码 代码分析:
这里使用了一个Promise已经封装过的ajax,我们从第一个接口中得到了帖子id,然后在then中的函数发送第二个请求(携带了第一个请求返回过来的参数),我们末了想要拿到第二个接口的结果,于是又有了一个then方法,但是在第一个then方法中要把一个新的Promise实例return出去,如许的话,第二个then才起作用!(这是由于then方法是Promise 实例所具有的方法,也就是说,then方法是定义在原型对象Promise.prototype上的)====>我们可以打印一下:console.log(Promise.prototype)

可以看的出来原型对象Promise.prototype中是有then方法的!
Promise.all()
Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
语法格式:
- const p = Promise.all([p1, p2, p3]);
复制代码 Promise.all()方法继承一个数组作为参数,p1、p2、p3都是 Promise 实例,假如不是,就会调用Promise.reslove() [该方法可自行相识]自动将参数转为 Promise 实例,再进一步处置惩罚。
说那么多白话没用,我们可以根据一个案例,就可以明确Promise.all()的用途了。
实际案例:
假如你想实现一个结果:在一个页面中,比及页面中全部的请求返回数据后,再渲染页面,该怎么实现呢?(在实际开辟中我们会看到loading加载页面,等数据返回完后,loading加载页面会消散,整个页面就显现出来了,加强用户的体验。)
实现思路:
通过Promise.all()方法,等多个接口全部吸收到数据后,再同一举行处置惩罚,然后渲染页面
代码如下:
- console.log("显示加载中")
- const q1 = pajax({
- url:"http://localhost:3000/looplist"
- })
- const q2 = pajax({
- url:"http://localhost:3000/datalist"
- })
- Promise.all([q1,q2]).then(res=>{
- console.log(res)
- console.log("隐藏加载中...")
- }).catch(err=>{
- console.log(err)
- })
复制代码 代码分析:
在上方代码中,全局打印体现加载中是取代loading的页面,体现该页面如今正是loading页面中,比及q1和q2所请求接口都得到返回的信息后,在then方法中吸收收据,而且可以举行渲染页面,同时隐藏了loading加载页面!
小结
岂论是在前端的项目开辟中还是在前端的口试过程中,Promise的职位就是举足轻重的,固然解决异步编程的终极解决方案是async和await,但是它们也是基于Promise封装而来的,在以往文章中,我就说过,学习编程重要的是搞懂某个技能是怎么实现的,而不是做一个cv侠,多去思考,才能进步。继续加油吧,少年!
书写不易,盼望各人可以或许给予三连支持,等待我更好的文章哟
来源:https://blog.csdn.net/m0_52040370/article/details/127197204
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |