Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >回调地狱解决方案之Promise

回调地狱解决方案之Promise

作者头像
用户1462769
发布于 2019-08-12 11:57:56
发布于 2019-08-12 11:57:56
1.4K00
代码可运行
举报
文章被收录于专栏:全栈者全栈者
运行总次数:0
代码可运行

为什么出现Promise

在javascript开发过程中,代码是单线程执行的,同步操作,彼此之间不会等待,这可以说是它的优势,但是也有它的弊端,如一些网络操作,浏览器事件,文件等操作等,都必须异步执行,针对这些情况,起初的操作都是使用回调函数实现。

实现方式如下(伪代码):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function One(callback) {
    if (success) {
        callback(err, result);
    } else {
        callback(err, null);
    }
}

One(function (err, result) {
    //执行完One函数内的内容,成功的结果回调回来向下执行
})

上述代码只是一层级回调,如果代码复杂后,会出现多层级的回调,代码可读性也会很差,那有没有一种方式,不用考虑里面的内容,直接根据结果成功还是失败执行下面的代码呢?有的,Promise(承诺),在ES6中对Promise进行了同意的规范。

Promise的含义

  • 书上这么说: Promise 是异步编程的一种解决方案,比传统的解决方案–回调函数和事件--更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了语法,原生提供了Promise 所谓Promise ,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。Promise 对象的状态不受外界影响
  • Promise/a+ 官方网站给出的定义 A promise represents the eventual result of an asyncchronous operation 翻译:表示一个异步操作的最终结果。
  • 我的理解: Promise使回调函数可以规范链式调用

Promise原理与讲解

原理
  1. Promise的三种状态
  • pending:进行中
  • fulfilled :执行成功
  • rejected :执行失败

注意Promise在某一时刻只能处于一种状态

  1. Promise的状态改变
  • pending------》fulfilled(resolved)
  • pending------》rejected

Promise的状态改变,状态只能由pending转换为rejected或者rejected,一旦状态改变完成后将无法改变(不可逆性)

用代码讲原理
  1. 创建一个Promise

创建Promise需要用到Promise的构造函数来实现,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var promise=new Promise(function(resolve,reject){
   // ...some async code 
   
   if(/* 一些异步操作成功*/)
   {
       resolve(value);
   }else
   {
       reject(error);
   }

})

代码分析

  • 在异步操作完成之后,会针对不同的返回结果调用resolve和reject。
  • resolve和reject是两个函数,resolve是异步操作成功时候被调用,将异步操作的返回值作为参数传递到外部;reject是异步操作出异常时候被调用,将错误信息作为参数传递出去。
  • ==Promise其实没有做任何实质的代码操作,它只是对异步操作回调函数的不同结果定义了不同状态。==
  • resolve函数和reject函数只是把异步结果传递出去
  1. 异步结果传递出去后,then来接 Promise对象将结果传递出来后,使用then方法来获取异步操作的值:代码如下:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
promise.then(function(value){
   //success
   
},function(error){

});

代码分析:

  • then方法将两个匿名函数作为参数,接收resolve和reject这两个函数的值。
  • value是执行成功的值,error是执行出错时的错误信息。
  • 对于error错误异常结果出现的时候,可以不单独写匿名错误的函数,可以直接用catch抛出
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
promise.then(function (data){
    //success
})
.catch(function(error){
  //error  
})
  • 注意then方法==只是==用来获取异步操作的值。
  1. then的返回值又是怎样呢?先看一段调用两次then的代码:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//之前创建promise操作后
promise.then(function(value){
    conlose.log(value);  //有值
}.then(function(value)
{
   conlose.log(value);   //未定义
});

代码分析:

  • 上面的第二个then方法中的值虽然是未定义,但是每一个then一定会==返回一个新的peomise对==象,但是默认是一个空对象。
  • 对于这个空对象我们如果想继续做一些什么,需要进行处理,可以用非空Promise对这个空的进行赋值覆盖,然后继续then的链式调用。
  • then 中的==retuen==关键字很重要,联系着下一个then的调用。
几个常用api
  • Promise.resolve resolve方法用来将一个非Promise对象转化为Promise对象

转换的对象是一个常量或者不具备状态的语句,转换后的对象自动处于resolve状态。转换的后的结果和原来一样

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var promise =Promise.resolve("hello world");
promise.then(function(result){
  console.log(result);   //输出结果 hello world
})

转换的对象如果直接是一个异步方法,不可以这么使用。

  • Promise.all(常用api) 多个promise需要执行的时候,可以使用promise.all方法统一声明,该方法可以将多个Promise对象包装成一个Promise。

代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
promise.all(
//一系列promise操作
).then(function(results){
    
    
}).catch(function(error){
    
});

代码分析:

  • promise.all对多有执行结果做一个包装传给了then
  • promise.all中的执行顺序是怎么样的,Promise的执行顺序是从被创建开始的,也就是在调用all的时候,==所有的promise都已经开始执行==了,all方法只是等到==所有的对象都执行完成==,才会把结果==传递给then==。
  • all中的promise,如果有一个状态变成了reject那么转换后的Promise字节变成reject,错误信息传递给catch,不会传递给then。(但是并不是说all这里面刚开始执行成功的操作就不算数了)

Promise在开发中的应用

项目开发中promise的应用代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise.all([
    self.count({phoneNumber: mobile, createdOn: {$gt: hour}}),
    self.count({ip: ip, createdOn: {$gt: hour}})
]).then(function (results) {
    if (results[0] >= 5) {
        return callback({code: -1, message: '短信发送频率过快,每手机号1小时内只能发送5次'});
    }
    if (results[1] >= 5) {
        return callback({code: -1, message: '短信发送频率过快,每IP1小时内只能发送5次'});
    }
    let code = {
        phoneNumber: mobile,
        code: tool.makeRandomStr(4, 1).toLowerCase(),
        createdOn: new Date(),
        expiredOn: new Date(new Date().getTime() + (20 * 60 * 1000)),			//20分钟失效
        ip: ip,
        isUsed: false
    };
    self.create(code, function (err, newCode) {
        if (newCode) {
            sms.sendSMS(mobile, newCode.code, 'ali', function (err, body) {
                console.log(body);
                if (err)
                    console.log("短信验证码发送失败:", err);
            });
            callback({code: 0, message: "验证码已经发送"});
        } else {
            callback({code: -1, message: "验证码发送失败,请重试"});
        }
    })
})

项目开发过程中使用promise.all的代码,当时是为了实现短信验证码发送前的校验功能。all中的两个promise,第一个是统计时间内该手机号发送验证码数量;第二个是统计时间内该ip发送验证码的数量。

Promise使用过程中注意事项(坑)

注意事项在上面原理讲解过程中,基本都提到过,只是重要的事情多说两遍。

  • 状态不可逆性
  • resolve函数和reject函数只是传递异步结果
  • then进行层级调用的时候,每次的返回值都一个空promise对象,如果想继续使用,赋值替换掉空promise对象,但是返回的时候return关键字很重要,不要忘了。
  • promise.all中的执行顺序是并行的,但是会等全部完成的结果传递给then
  • ==执行顺序==,promise是then方法调用之后才会执行吗?还是从创建那一刻就开始执行?promise从创建那一刻就开始执行,只是把结果传递给了then,then与promise的执行无关。

Promise的反思

Promise的讲解就到这里,但是大家在开发过程中,会发现有些时候多次操作异步会出现很多层级的调用,也就是

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
promise.then(...)

.then(...)

.then(...)

这种情况,代码虽然看起来会比callback的回调简介和规范了很多,但是还是感觉一些复杂,有没有更好的解决办法呢?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全栈者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
前端面试官问Promise,怎样回答拿高分
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
程序媛夏天
2024/01/18
2810
ES6之Promise
Promise JS是单线程的 就是同一个时间只能处理一个任务。就类似生活中的去超市排队结账,正常情况下,一位收银员只能为一位顾客结账,其他顾客需要在后面排队等候。 为什么 JS 是单线程的?作为浏览器脚本语言,JavaScript 的主要用途是与用户互动,以及操作 DOM 。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定 JavaScript同时有两个线程,一个线程在某个 DOM 节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准? 单线程就意味着,
19组清风
2021/11/15
8150
ES6之Promise
初识Promise
Promise是异步编程的一种优雅的解决方案。它相比于回调和事件交互,更加合理和强大。它改善了深度回调的问题。 回调里面还有回调,层级较深的,代码看起来特别凌乱。而通过事件交互会多做一些工作,比如发送事件,监听事件,事件回调等操作。而Promise能够获取异步操作的结果,这样的话,方便进一步处理接下来的逻辑。
Umbrella1024
2021/03/23
5720
ES6-标准入门·异步编程 Promise
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理且更强大。,ES6 将其写进了语言标准,并原生提供了 Promise 对象。
数媒派
2022/12/01
4580
Javascript异步回调细数:promise yield async/await
虽然我对js的鄙视一直都是无以复加,但是奈何前端环境不得不依赖javascript。哪些nodejs的大神们四处布道nodejs统治一切:单线程非阻塞,高IO操作。但是,java也可以做好吧,而且GO做的更干练!假设你的应用程序要做两件事情,分别是A和B。你发起请求A,等待响应,出错。发起请求B,等待响应,出错。Go语言的阻塞模型可以非常容易地处理这些异常,而换到了Node里,要处理异常就要跳到另一个函数里去,事情就会变得复杂。
周陆军博客
2023/05/07
9610
ES6中的Promise深入学习
Promise是异步编程的一种新的解决方案,比传统的解决方案(纯回调函数)更加的方便和强大。简单来说,Promise就是一个容器,里面保存着某个未来才会结束的事情(通常是一个异步操作的结果)。
帅的一麻皮
2020/07/14
1.3K0
《深入浅出Node.js》:Node异步编程解决方案 之 ES6 Promise
在上一篇讲了异步编程解决方案之一的事件发布-订阅模式,使用事件模式时,执行流程需要被预先设定。即便是分支,也需要预先设定,这是由发布-订阅模式的运行机制决定的。这个方法的灵活性比较受限,那是否有一种先执行异步调用,延迟传递处理的方式呢?在ES6发布之前,解决方案是Promise/Deferred模式,现在则推荐ES6官方提供的Promise。
前端_AWhile
2019/08/29
9720
什么是回调地狱?如何解决回调地狱问题_地狱回调
这个问题呢,需要从Node.js的API说起,这里就会有人问了?博主你不是说回调地狱的问题吗,怎么说到API了,别急,看博主一步一步的解释给你听:
全栈程序员站长
2022/11/15
3.9K0
ES6之Promise用法详解
本文主要对ES6的Promise进行一些入门级的介绍。要想学习一个知识点,肯定是从三个方面出发,what、why、how。下面就跟着我一步步学习吧~
半指温柔乐
2019/03/06
1.3K0
ES6之Promise用法详解
[前端学习]Promise 对象一网打尽
Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
Maynor
2021/12/07
1K0
es6 Promise
Promise 是异步编程的一种方案,简单说就是一个容器,里面保存着某个未来才会结束的事件的 结果,Promise 是一个对象,从它,可以获取异步操作的消息。 Promise 对象有以下两个特点。   (1)对象的状态不受外界影响。Promise 对象代表一个异步操作,有是三种状态。pendding     (进行中),fulfilled(已成功)和rejected(已失败)。   (2)一旦状态改变,就不会在变,任何时候都可以得到这个结果,Promise 对象的状态改变   只有两种可能: 从pendin
用户1197315
2018/01/22
7580
promise & axios & async_await 关于 Promise
Promise 是ES6里面异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。 简单说Promise 就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。 有三种状态,pending(进行中)、resolved(已完成)、rejected(已失败),特点是只有异步操作的结果,可以决定当前是哪一种状态,状态一旦改变,就无法再次改变状态;
前端小tips
2021/11/24
1.7K0
promise & axios & async_await 关于 Promise
JavaScript执行——Promise
  Promise构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve和 reject。它们是两个函数,由JavaScript引擎提供,不用自己部署。 resolve作用是将Promise对象状态由“未完成”变为“成功”,也就是 Pending->Fulfilled,在异步操作成功时调用,并将异步操作的结果作为参数传递出去;而reject函数则是将Promise对象状态由“未完成”变为“失败”,也就是 Pending->Rejected,在异步操作失败时调用,并将异步操作的结果作为参数传递出去。
流眸
2019/08/12
7680
JavaScript执行——Promise
ES6异步处理解决方案
通常把从未决推向已决的resolved状态的过程叫做resolve,从未决推向已决的rejected状态的过程,叫做reject
javascript艺术
2021/05/28
8730
ES6异步处理解决方案
【javascript】异步编年史,从“纯回调”到Promise
啦啦啦321
2018/01/03
1.3K0
【javascript】异步编年史,从“纯回调”到Promise
promise的使用方法
异步操作作为JavaScript中的一大特色,解决了JavaScript单线程运行的一个难题,但是很多时候有问题也在于这上面。最大的问题之一,就是异步操作过多的时候,代码内会充斥着众多回调函数,乃至形成回调金字塔。为了解决回调函数带来的问题,Promise作为一种更优雅的异步解决方案被提出,最初只是一种实现接口规范,而到了es6,则是在语言层面就原生支持了Promise对象。
OECOM
2020/07/02
7110
JavaScript中的Promise使用详解
熟悉前端开发的都一定写过回调方法(callback),简单的说,回调方法是一个函数被作为参数传递给另一个函数,比如下面的代码
青年码农
2020/11/11
1.6K0
Promise用法及使用案例
想了解更多方法请参考阮一峰老师的教程:http://es6.ruanyifeng.com/#docs/promise
全栈程序员站长
2022/07/04
5760
Promise用法及使用案例
Promise对象
JavaScript是单线程的语言,通过维护执行栈与任务队列而实现了异步操作,setTimeout与Ajax就是典型的异步操作,Promise就是异步操作的一个解决方案,用于表示一个异步操作的最终完成或失败, 及其结果值,Promise有各种开源实现,在ES6中被统一规范,由浏览器直接支持。
WindRunnerMax
2020/08/27
6410
通俗的解释什么是Promise
MDN的解释: Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象。
全栈程序员站长
2022/08/31
9750
通俗的解释什么是Promise
相关推荐
前端面试官问Promise,怎样回答拿高分
更多 >
交个朋友
加入架构与运维工作实战群
高并发系统设计 运维自动化实践
加入前端工作实战群
前端工程化实践 组件库开发经验分享
加入[后端] 腾讯云技术交流站
后端架构设计 高可用系统实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档