热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

js异步回调之Promise

先上一个大家比较熟悉的例子;以前我们写jqueryajax请求的时候,都是这样写:$.ajax({url:test.json,succ

先上一个大家比较熟悉的例子;
以前我们写jquery ajax请求的时候,都是这样写:

$.ajax({url: "test.json",success: function(){alert("hello world!");},error:function(){alert("error");}});

后来呢在jquery1.7版本后,我们开始这样写:

$.ajax("test.json").done(function(){ alert("hello world!"); }).fail(function(){ alert("error"); });

很明显,更改后的代码更易懂易读了。
这个是jquery的deferred对象,jquery deferred对象就是jQuery对Promises的实现,还其他有很多实现了promises的库供开发者可用。 像微软的 WinJS.Promise, when.js, q, 和dojo.Deferred,它们暴露的都是deferred对象。Promise也已经纳入了ES6,对于jQuery实现Promises我们暂时就不讲了,今天的目的是Promise。

那Promise到底是怎么回事呢?

其实呢,Promise就是一个对象,它是用来实现异步操作的,它可以让异步代码书写起来更优雅,更便于阅读。

Promise的特性:
1、Promise对象有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败),只有异步操作结果可以改变当前状态,其他操作不能改变状态,Promise对象的状态只能从“进行中”改为“已完成”或者从“进行中”改为“失败”。

2、Promise对象的then方法,就是用来指定回调函数。一旦非同步操作完成,就调用指定的回调函数,并总是返回一个promise对象,方便链式调用。而且同一个promise的then可以调用多次。

3、then方法接受两个回调函数作为参数,第一个参数是成功Resolved时的回调,第二个是失败Reject时的回调。第二个参数是可以选的,同时,then可以接受另一个promise传入,也接受一个“类then”的对象或方法,即thenable对象。
我们现在用promise来组织一下代码。

var sleep = function (time) {return new Promise(function (resolve, reject) {console.log('test123');setTimeout(function () {resolve('test');}, time);})
};
(function(){console.log('start');sleep(3000).then(function(data){console.log(data);return sleep(5000);}).then(function(data){console.log(data);console.log('end');})
})();

上面代码中,sleep方法返回一个Promise实例,表示一段时间以后才会发生的结果。首先输出‘start’,然后,sleep执行后,3秒后返回“test”,触发then方法绑定的回调函数,输出回调返回值“test”,又return sleep(5000),这样第一个then的返回值,就是第二个的参数,再次执行sleep,5秒后返回‘test’,输出‘test’、'end';

好像没有什么大不了的,promises的真正强大之处在于多重的链接,在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了:它有个缺点就是链过长以后,满屏幕的then,傻傻分不清业务到底干啥了,

Promise的 api

1、Promise.resolve()
2、Promise.reject()
3、Promise.prototype.then()
4、Promise.prototype.catch()
5、Promise.all() // 所有的都有完成,相当于 且
6、Promise.race() // 完成一个即可,相当于 或

1、Promise.resolve()的作用将现有对象转为Promise对象resolvedl;
Promise.resolve('test')==new Promise(resolve=>resolve('test'))
2、Promise.reject()也是返回一个Promise对象,状态为rejected;

let p=Promise.reject('error') == let p=new Promise((resolve,reject)=>reject('error'));p.catch(data=>{console.log(data);})

生成一个Promise对象的实例对象p,抛出错误,状态就会变为Rejected,调用p.catch()指定的回调函数。
3、.then()方法,then方法是定义在原型对象Promise.prototype上的,作用是为Promise 对象添加回调函数。

let p=new Promise(resolve=>resolve('hello'));
p.then((resolve,reject)=>{console.log(resolve);
}).then(function(){console.log('zhangsan');
})

then方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数。 可以使用链式操作,指定多个then(),依次执行,上面的代码输出结果:’hello‘,'zhangsan'
4、.catch():发生错误的回调函数,同样,catch方法也是定义在原型对象Promise.prototype上的,事例同Promise.reject()的例子。注:如果Promise的状态已经变为resolved,再抛出错误是无效的。

var p = new Promise(function(resolve, reject) {resolve('success');reject('fail');
});
p.then(function(value) { console.log(value) }).catch(function(error) { console.log(error) });

输出结果:success;
5、Promise.all()的作用是同时执行多个实例,同步并行,且所以的实例都返回resolve状态,Promise才会改变为resolve状态,其中一个为rejected,promise的状态就是rejected;
注:Promise.all 方法的参数可以不是数组,但是必须是一个Iterator接口对象,且返回promise实例,否则报错:error:TypeError: [object Promise] is not iterable!

let p1 =new Promise(function(resolve,reject){resolve(1);
});
let p2 = new Promise(function(resolve,reject){resolve(2);});
let p3 = new Promise(function(resolve,reject){// reject();resolve(3);});
Promise.all([p1, p2, p3]).then(function (results) {console.log('success:'+results);
}).catch(function(r){console.log("error");console.log(r);
});

上面代码输出:success:1,2,3;
把 p3方法改为返回 reject();输出结果是:error;
6、Promise.race()的作用也是同时执行多个实例,只要有一个实例改变状态,Promise就改为那个实例所改变的状态;

let p1 =new Promise(function(resolve,reject){setTimeout(function(){reject(1);},3000)
});
let p2 = new Promise(function(resolve,reject){setTimeout(function(){resolve(2);},1000)
});
Promise.race([p1, p2]).then(function (results) {console.log('success:'+results);
}).catch(function(results){console.log("error:"+results);
});
输出:success: 2;

上面代码p2首先执行完毕,改变状态为resolve,所以promise的状态被改为resolve;
我们把p1的时间改为1000,p2改为3000,也就是说p1先执行完毕,promise的状态也被改变为reject,输出:error:1

如果想深入学习,可以看一下阮一峰的《ES 6标准入门》的Promise部分http://es6.ruanyifeng.com/#do...,很详细的。



推荐阅读
  • 深入解析ES6至ES8的新特性与应用
    本文详细介绍了自2015年发布的ECMAScript 6.0(简称ES6)以来,JavaScript语言的多项重要更新,旨在帮助开发者更好地理解和利用这些新特性进行复杂应用的开发。 ... [详细]
  • JavaScript 中创建对象的多种方法
    本文详细介绍了 JavaScript 中创建对象的几种常见方式,包括对象字面量、构造函数和 Object.create 方法,并提供了示例代码和属性描述符的解释。 ... [详细]
  • JavaScript中的数组是数据集合的核心结构之一,内置了多种实用的方法。掌握这些方法不仅能提高开发效率,还能显著提升代码的质量和可读性。本文将详细介绍数组的创建方式及常见操作方法。 ... [详细]
  • 本文将继续探讨前端开发中常见的算法问题,重点介绍如何将多维数组转换为一维数组以及验证字符串中的括号是否成对出现。通过多种实现方法的解析,帮助开发者更好地理解和掌握这些技巧。 ... [详细]
  • 本文深入探讨了JavaScript中实现继承的四种常见方法,包括原型链继承、构造函数继承、组合继承和寄生组合继承。对于正在学习或从事Web前端开发的技术人员来说,理解这些继承模式对于提高代码质量和维护性至关重要。 ... [详细]
  • 微信小程序中实现位置获取的全面指南
    本文详细介绍了如何在微信小程序中实现地理位置的获取,包括通过微信官方API和腾讯地图API两种方式。文中不仅涵盖了必要的准备工作,如申请开发者密钥、下载并配置SDK等,还提供了处理用户授权及位置信息获取的具体代码示例。 ... [详细]
  • 本文探讨了浏览器的同源策略限制及其对 AJAX 请求的影响,并详细介绍了如何在 Spring Boot 应用中优雅地处理跨域请求,特别是当请求包含自定义 Headers 时的解决方案。 ... [详细]
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • 12月16日JavaScript变量、函数、流程、循环等***线上九期班
    12月16日JavaScript变量、函数、流程、循环等***线上九期班 ... [详细]
  • 云函数与数据库API实现增删查改的对比
    本文将深入探讨使用云函数和数据库API实现数据操作(增删查改)的不同方法,通过详细的代码示例帮助读者更好地理解和掌握这些技术。文章不仅提供代码实现,还解释了每种方法的特点和适用场景。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 本文探讨了如何在Classic ASP中实现与PHP的hash_hmac('SHA256', $message, pack('H*', $secret))函数等效的哈希生成方法。通过分析不同实现方式及其产生的差异,提供了一种使用Microsoft .NET Framework的解决方案。 ... [详细]
  • 本文详细介绍了如何使用 HTML 和 CSS 对文件上传按钮进行样式美化,使用户界面更加友好和美观。 ... [详细]
  • 一个登陆界面
    预览截图html部分123456789101112用户登入1314邮箱名称邮箱为空15密码密码为空16登 ... [详细]
  • 理解文档对象模型(DOM)
    本文介绍了文档对象模型(DOM)的基本概念,包括其作为HTML文档的节点树结构,以及如何通过JavaScript操作DOM来实现网页的动态交互。 ... [详细]
author-avatar
谁的围脖搞笑排行榜
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有