今天来学习下Promise吧,其实这在笔试上也是一个考点.javascript
Promise对象是CommonJS(熟悉的名字吧- -)工做组提出的规范.Promise本来只是社区提出的构想,一些外部函数库率先实现了该功能,ES6中将其写入了语言标准.
目的:为异步操做提供统一接口java
Promise是啥,它就是一个javascript中一个对象,起着代理做用,充当异步操做与回调函数之间的中介.
避免相似于ajax
这种嵌套地狱的产生.让咱们的代码变得更加简单易读
使用了Promise,你们都说好json
(new Promise(f1).then(f2));
总结:Promise使得异步操做的向下发展变成横向发展,程序流程变得清晰,易于阅读.数组
异步任务返回一个Promise对象,它有三种状态promise
pending(未完成)异步
resolved,fulfilled(已完成)ide
rejected(失败)函数
它有两种变化途径工具
pending --> resolved/fulfilled
pending --> rejected
它有两种结果
异步操做成功,返回一个值,状态变为resolved
异步操做失败,抛出一个错误,状态变为rejected
Promise使用.then()方法添加回调函数,then接收两个回调函数,第一个为成功时的回调函数,另外一个为失败时的回调函数.主要为状态改变时调用相对的回调函数.
并且then能够链式调用.
Promise构造函数接受一个函数做为参数,而该函数两个参数分别是resolve和reject.它们由JS引擎提供,不须要本身部署.
Promise(function(resolve,reject){})
resolve函数做用为:将Promise对象从未完成变为成功(Pending->Resolved),异步操做成功时调用,并将异步操做的结果做为参数传递出去.
reject函数做用为:将Promise对象从未完成变为失败(Pending->Rejected),异步操做失败时调用,并将异步操做报出的错误做为参数传递出去.
Promise.then()方法能够用于指定Resolved状态和Reject状态的回调函数.
promise.then(function(value){//成功+_+!},function(value){//失败Q_Q});
咱们只想对异常进行处理时能够采用promise.then(undefined, onRejected)这种方式,或者promise.catch(onRejected)
!注意!此处有坑,接下来在深刻节会进行讲解
Promise.all()方法接收一个promise对象的数组为参数,当这个数组中全部的Promise对象所有变成resolve/reject状态的时候,才会调用.then方法,其中传入的promise是同时开始,并行执行的.
promise.all([promise1,promise2,.....]);
Promise.race()方法和Promise.all()方法同样接收一个promise对象的数组做为参数,可是数组中有一个promise对象进入fulfilled或rejected状态,就会开始后续处理.
promise.race([promise1,promise2,.....]);
Promise.resolve(42); //等价于 new Promise(function(resolve){ resolve(42); }); Promise.reject(new Error("出错了")); //等价于 new Promise(function(resolve,reject){ reject(new Error("出错了")); });
这是很是相似于Promise的东西,拥有.then方法.
其中比较经典的例子就是jQuery.ajax()返回的值就是thenable的.
var promise = Promise.resolve($.ajax('/json/comment.json'));
这样就能够将thenable对象转化为promise对象
传送门:Promise.resolve()
看代码就能明白这个地方的问题了.
var promise = new Promise(function (resolve){ console.log("inner promise"); // 1 resolve(42); }); promise.then(function(value){ console.log(value); // 3 }); console.log("outer promise"); // 2 //结果是 /* inner promise // 1 outer promise // 2 42 // 3 */
能够看出,即便咱们调用promise.then时promise对象已经肯定状态,Promise也会以异步的方式调用回调函数,这就是Promise设计上的规定方针.
每次调用then/catch,都会返回一个promise对象,这一点上咱们经过使用===就能够判断出来每次promise对象其实都是不同的
这点和上一点联合起来很容易理解
直接上图吧,来自于JavaScript Promise迷你书(中文版)
在结合咱们的代码吧
// <1> onRejected不会被调用 function badMain(onRejected) { return Promise.resolve(42).then(throwError, onRejected); } // <2> 有异常发生时onRejected会被调用 function goodMain(onRejected) { return Promise.resolve(42).then(throwError).catch(onRejected); }
onFullfilled中发生的错误,如在<1>里面throwError中的错误,是不会致使onRejected的执行(捕获异常)的,咱们只能经过后面的catch方法才能捕获.
不兼容就是用polyfill吧
关于IE8以及如下版本中,catch会因为在ES3中为保留字,致使identifier not found错误,对此咱们能够经过["catch"]或者then(undefined,function(){})来进行catch,而某些类库中,采用了caught做为函数名来规避该问题.值得注意的是,有不少压缩工具中自带了.catch转["catch"]
应用示例:
加载图片
var preloadImage = function(path){ return new Promise(function(resolve,reject){ var image = new Image(); image.onload = resolve; image.onerror = reject; image.src = path; }) } preloadImage("https://dn-anything-about-doc.qbox.me/teacher/QianDuan.png").then(function(){ alert("图片加载成功"); },function(){ alert("图片加载失败"); })
Ajax操做
function search(term) { var url = 'http://example.com/search?q=' + term; var xhr = new XMLHttpRequest(); var result; var p = new Promise(function(resolve, reject) { xhr.open('GET', url, true); xhr.onload = function(e) { if (this.status === 200) { result = JSON.parse(this.responseText); resolve(result); } }; xhr.onerror = function(e) { reject(e); }; xhr.send(); }); return p; } search("Hello World").then(console.log, console.error);
回到最初吧,其实Promise对象优势仍是在于规范的链式调用,能够清晰看出程序流程.而且对于错误还能定义统一的处理方法.