Promise

本文探讨了JavaScript中Promise的概念及其如何简化复杂的异步编程。通过使用Promise,开发者可以将原本难以维护的嵌套回调转化为易于理解的链式调用,从而提高代码的可读性和可维护性。

转载自: https://segmentfault.com/a/1190000002395343
什么是Promise?
在说Promise之前,不得不说一下JavaScript的嵌套的回调函数
在JavaScript语言中,无论是写浏览器端的各种事件处理回调、ajax回调,还是写Node.js上的业务逻辑,不得不面对的问题就是各种回调函数。回调函数少了还好,一旦多了起来而且必须讲究执行顺序的话,回调函数开始嵌套,那代码的恶心程度是相当不符合常人的线性思维的。

说到这里,我真有点想去了解一下响马老师的fibjs,我没有接触过它,但它的编程方式就是线性的,更加符合常人思维。我个人认为Promise就是为了把JS复杂的嵌套转换成常人思维的线性代码。
// 就像下面这样:
// 你不在乎下面这三个ajax的执行顺序还好
// 如果你在乎顺序呢?
$.get(‘url’, function(){

}, ‘json’);
$.get(‘url1’, function(){

}, ‘json’);
$.get(‘url2’, function(){

}, ‘json’);

// 就像这样?
.get(‘url’, function(){.get(‘url1’, function(){
$.get(‘url2’, function(){

    }, 'json');
}, 'json');

}, ‘json’);

// 下面是我最近写的一段Node.js的代码
// 其实这个嵌套也不算多
// 如果业务逻辑相当复杂起来呢?
// 嵌套20 30层?
var adminIndex = function(params, callback){
storeAdmin.getApiTokens(function(err, tokens){
if ( err ) { callback(err); return; }
storeAdmin.getApiServices(function(err, apiServices){
if ( err ) { callback(err); return; }
storeAdmin.getSocketioServices(function(err, socketioServices){
if ( err ) { callback(err); return; }
callback(0, {
status : true,
data : {
api_tokens : tokens,
api_services : apiServices,
socketio_services : socketioServices
}
});
});
});
});
};
说了这么多,到底什么是Promise呢?
其实,Promise就是一个类,而且这个类已经成为了ES6的标准,这个类目前在chrome32、Opera19、Firefox29以上的版本都已经支持了,要想在所有浏览器上都用上的话就看看es6-promise吧。

那Promise怎么用呢?
看一段很简单的代码,请注意阅读代码中的注释。

var val = 1;

// 我们假设step1, step2, step3都是ajax调用后端或者是
// 在Node.js上查询数据库的异步操作
// 每个步骤都有对应的失败和成功处理回调
// 需求是这样,step1、step2、step3必须按顺序执行
function step1(resolve, reject) {
console.log(‘步骤一:执行’);
if (val >= 1) {
resolve(‘Hello I am No.1’);
} else if (val === 0) {
reject(val);
}
}

function step2(resolve, reject) {
console.log(‘步骤二:执行’);
if (val === 1) {
resolve(‘Hello I am No.2’);
} else if (val === 0) {
reject(val);
}
}

function step3(resolve, reject) {
console.log(‘步骤三:执行’);
if (val === 1) {
resolve(‘Hello I am No.3’);
} else if (val === 0) {
reject(val);
}
}

new Promise(step1).then(function(val){
console.info(val);
return new Promise(step2);
}).then(function(val){
console.info(val);
return new Promise(step3);
}).then(function(val){
console.info(val);
return val;
}).then(function(val){
console.info(val);
return val;
});

// 执行之后将会打印
步骤一:执行
Hello I am No.1
步骤二:执行
Hello I am No.2
步骤三:执行
Hello I am No.3
Hello I am No.3
Promise到底解决什么问题?
正如上面代码所示,笔者认为,Promise的意义就在于 then 链式调用 ,它避免了异步函数之间的层层嵌套,将原来异步函数的 嵌套关系 转变为便于阅读和理解的 链式步骤关系 。
Promise的主要用法就是将各个异步操作封装成好多Promise,而一个Promise只处理一个异步逻辑。最后将各个Promise用链式调用写法串联,在这样处理下,如果异步逻辑之间前后关系很重的话,你也不需要层层嵌套,只需要把每个异步逻辑封装成Promise链式调用就可以了。

Promise常用的关键点
在Promise定义时,函数已经执行了

Promise构造函数只接受一个参数,即带有异步逻辑的函数。这个函数在 new Promise 时已经执行了。只不过在没有调用 then 之前不会 resolve 或 reject。

在then中的resolve方法中如何return?

在then方法中通常传递两个参数,一个 resolve 函数,一个 reject 函数。reject暂时不讨论,就是出错的时候运行的函数罢了。resolve 函数必须返回一个值才能把链式调用进行下去,而且这个值返回什么是有很大讲究的。

resolve 返回一个新 Promise
返回一个新Promise之后再调用的then就是新Promise中的逻辑了。

resolve 返回一个值
返回一个值会传递到下一个then的resolve方法参数中。

基于模拟退火的计算器 在线运行 访问run.bcjh.xyz。 先展示下效果 https://pan.quark.cn/s/cc95c98c3760 参见此仓库。 使用方法(本地安装包) 前往Releases · hjenryin/BCJH-Metropolis下载最新 ,解压后输入游戏内校验码即可使用。 配置厨具 已在2.0.0弃用。 直接使用白菜菊花代码,保留高级厨具,新手池厨具可变。 更改迭代次数 如有需要,可以更改 中39行的数字来设置迭代次数。 本地编译 如果在windows平台,需要使用MSBuild编译,并将 改为ANSI编码。 如有条件,强烈建议这种本地运行(运行可加速、可多次重复)。 在 下运行 ,是游戏中的白菜菊花校验码。 编译、运行: - 在根目录新建 文件夹并 至build - - 使用 (linux) 或 (windows) 运行。 最后在命令行就可以得到输出结果了! (注意顺序)(得到厨师-技法,表示对应新手池厨具) 注:linux下不支持多任务选择 云端编译已在2.0.0弃用。 局限性 已知的问题: - 无法得到最优解! 只能得到一个比较好的解,有助于开阔思路。 - 无法选择菜品数量(默认拉满)。 可能有一定门槛。 (这可能有助于防止这类辅助工具的滥用导致分数膨胀? )(你问我为什么不用其他语言写? python一个晚上就写好了,结果因为有涉及json读写很多类型没法推断,jit用不了,算这个太慢了,所以就用c++写了) 工作原理 采用两层模拟退火来最大化总能量。 第一层为三个厨师,其能量用第二层模拟退火来估计。 也就是说,这套方法理论上也能算厨神(只要能够在非常快的时间内,算出一个厨神面板的得分),但是加上厨神的食材限制工作量有点大……以后再说吧。 (...
08-16
### Promise 在异步编程中的角色 Promise 是一种用于处理异步操作的解决方案,它在语法上是一个 ES6 的原生对象,代表了未来将要发生的事件,用来传递异步操作的消息。从本质上讲,Promise 是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。 Promise 提供了一个统一的 API,使得各种异步操作可以使用相同的方法进行处理。这意味着无论异步操作的结果是成功还是失败,都可以通过 Promise 的 API 来处理这些结果。 Promise 对象有两个主要的状态变化:从 pending(等待)变为 fulfilled(已成功)或 rejected(已失败)。一旦状态改变,就不会再变,这保证了 Promise 的结果是不可逆的。 下面是一个简单的 Promise 使用示例: ```javascript var p1 = new Promise(function(resolve, reject) { // 异步操作 resolve('OK'); // 或者 reject('Error'); }); p1.then(function(rs) { // 如果 p1 的状态变为 resolved,则执行此函数,并且 rs 会接收到 'OK' }).catch(function(rs) { // 如果 p1 的状态变为 rejected,则执行此函数,并且 rs 会接收到 'Error' }).finally(function() { // 不论 p1 的状态如何,finally 中的函数一定会执行 }); ``` 此外,Promise 还提供了 `Promise.all()` 方法,该方法接收一个 Promise 数组,并返回一个新的 Promise。只有当数组中的所有 Promise 都成功完成时,这个新的 Promise 才会成功,并且其结果是一个包含所有 Promise 结果的数组。 ```javascript let p1 = new Promise((resolve, reject) => { resolve('OK'); }); let p2 = Promise.reject('error'); // 修改为 reject 以展示错误处理 let p3 = Promise.resolve('Oh Year!'); const result = Promise.all([p1, p2, p3]); console.log(result); ``` 在这个例子中,由于 p2 被设置为 rejected,所以整个 Promise.all 的结果也会是 rejected。如果希望即使有一个失败也要继续执行其他 Promise,可以考虑使用 `Promise.allSettled()` 方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值