【JS】302- 回调地狱解决方案之Promise


为什么出现Promise

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

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

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

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

Promise的含义

Promise原理与讲解

原理
  1. Promise的三种状态

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

  1. Promise的状态改变

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

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

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

var promise=new Promise(function(resolve,reject){	
   // ...some async code 	
   	
   if(/* 一些异步操作成功*/)	
   {	
       resolve(value);	
   }else	
   {	
       reject(error);	
   }	
	
})

代码分析:

  1. 异步结果传递出去后,then来接 Promise对象将结果传递出来后,使用then方法来获取异步操作的值:代码如下:

promise.then(function(value){	
   //success	
   	
},function(error){	
	
});

代码分析:

promise.then(function (data){	
    //success	
})	
.catch(function(error){	
  //error  	
})
  1. then的返回值又是怎样呢?先看一段调用两次then的代码:

//之前创建promise操作后	
promise.then(function(value){	
    conlose.log(value);  //有值	
}.then(function(value)	
{	
   conlose.log(value);   //未定义	
});

代码分析:

几个常用api

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

var promise =Promise.resolve("hello world");	
promise.then(function(result){	
  console.log(result);   //输出结果 hello world	
})

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

代码如下

promise.all(	
//一系列promise操作	
).then(function(results){	
    	
    	
}).catch(function(error){	
    	
});

代码分析:

Promise在开发中的应用

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

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使用过程中注意事项(坑)

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

Promise的反思

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

promise.then(...)	
	
.then(...)	
	
.then(...)

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

回调的终极使用--async和await的讲解

▼原创系列推荐▼1.JavaScript 重温系列(22篇全)
2.ECMAScript 重温系列(10篇全)
3.JavaScript设计模式 重温系列(9篇全)
4.正则 / 框架 / 算法等 重温系列(16篇全)

640?wx_fmt=png

640?wx_fmt=png你点的每个赞,我都认真当成了喜欢
个人博客:http://www.pingan8787.com 微信公众号【前端自习课】和千万网友一起,每日清晨,享受一篇前端优秀文章。 目前已连续推送文章 600+ 天,愿每个人的初心都能一直坚持下去!
原文地址:https://www.cnblogs.com/pingan8787/p/11838146.html