Promise对象的基础入门学习

pxup3654 8年前
   <p>Promise对象是CommonJS工作组提出的规范。Promise原本只是社区提出的构想,一些外部函数库率先实现了该功能,ES6中将其写入了语言标准。Promise是啥,它就是一个javascript中一个对象,起着代理作用,充当异步操作与回调函数之间的中介。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/12520a2a80eb85955e65ca162225e8c7.jpg"></p>    <p>今天来学习下Promise吧,其实这在笔试上也是一个考点.</p>    <h3><strong>基本介绍</strong></h3>    <p>Promise对象是CommonJS(熟悉的名字吧- -)工作组提出的规范.Promise原本只是社区提出的构想,一些外部函数库率先实现了该功能,ES6中将其写入了语言标准.</p>    <p>目的:为异步操作提供统一接口</p>    <p>Promise是啥,它就是一个javascript中一个对象,起着代理作用,充当异步操作与回调函数之间的中介.</p>    <p>避免类似于</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b8673ff707ccf326197d67edd7bf5dc8.png"></p>    <p>这种嵌套地狱的产生.让我们的代码变得更加简单易读使用了Promise,大家都说好</p>    <pre>  <code class="language-javascript">(new Promise(f1).then(f2));   </code></pre>    <p>总结:Promise使得异步操作的向下发展变成横向发展,程序流程变得清晰,易于阅读.</p>    <h3><strong>基本思想</strong></h3>    <ul>     <li>异步任务返回一个Promise对象,它有三种状态</li>    </ul>    <p>1.pending(未完成)</p>    <p>2.resolved,fulfilled(已完成)</p>    <p>3.rejected(失败)</p>    <ul>     <li>它有两种变化途径</li>    </ul>    <p>1.pending --> resolved/fulfilled</p>    <p>2.pending --> rejected</p>    <ul>     <li>它有两种结果</li>    </ul>    <p>1.异步操作成功,返回一个值,状态变为resolved</p>    <p>2.异步操作失败,抛出一个错误,状态变为rejected</p>    <p>Promise使用.then()方法添加回调函数,then接收两个回调函数,第一个为成功时的回调函数,另一个为失败时的回调函数.主要为状态改变时调用相对的回调函数.</p>    <p>而且then可以链式调用.</p>    <h3><strong>基本使用</strong></h3>    <p>Promise构造函数接受一个函数作为参数,而该函数两个参数分别是resolve和reject.它们由JS引擎提供,不需要自己部署.</p>    <pre>  <code class="language-javascript">Promise(function(resolve,reject){})   </code></pre>    <p>resolve函数作用为:将Promise对象从未完成变为成功(Pending->Resolved),异步操作成功时调用,并将异步操作的结果作为参数传递出去.</p>    <p>reject函数作用为:将Promise对象从未完成变为失败(Pending->Rejected),异步操作失败时调用,并将异步操作报出的错误作为参数传递出去.</p>    <p>Promise.then()方法可以用于指定Resolved状态和Reject状态的回调函数.</p>    <pre>  <code class="language-javascript">promise.then(function(value){//成功+_+!},function(value){//失败Q_Q});   </code></pre>    <p>我们只想对异常进行处理时可以采用promise.then(undefined, onRejected)这种方式,或者promise.catch(onRejected)</p>    <p>!注意!此处有坑,接下来在深入节会进行讲解</p>    <p>Promise.all()方法接收一个promise对象的数组为参数,当这个数组中所有的Promise对象全部变成resolve/reject状态的时候,才会调用.then方法,其中传入的promise是同时开始,并行执行的.</p>    <pre>  <code class="language-javascript">promise.all([promise1,promise2,.....]);   </code></pre>    <p>Promise.race()方法和Promise.all()方法一样接收一个promise对象的数组作为参数,但是数组中有一个promise对象进入fulfilled或rejected状态,就会开始后续处理.</p>    <pre>  <code class="language-javascript">promise.race([promise1,promise2,.....]);   </code></pre>    <h3><strong>相关的语法糖</strong></h3>    <pre>  <code class="language-javascript">Promise.resolve(42);   //等价于   new Promise(function(resolve){       resolve(42);   });      Promise.reject(new Error("出错了"));   //等价于   new Promise(function(resolve,reject){       reject(new Error("出错了"));   });    </code></pre>    <h3><strong>深入</strong></h3>    <p>关于Thenable对象</p>    <p>这是非常类似于Promise的东西,拥有.then方法.</p>    <p>其中比较经典的例子就是jQuery.ajax()返回的值就是thenable的.</p>    <pre>  <code class="language-javascript">var promise = Promise.resolve($.ajax('/json/comment.json'));   </code></pre>    <p>这样就可以将thenable对象转化为promise对象</p>    <p>传送门:Promise.resolve()</p>    <p>关于promise设计:总是异步操作</p>    <p>看代码就能明白这个地方的问题了.</p>    <pre>  <code class="language-javascript">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   */    </code></pre>    <p>可以看出,即使我们调用promise.then时promise对象已经确定状态,Promise也会以异步的方式调用回调函数,这就是Promise设计上的规定方针.</p>    <h3><strong>关于调用then/catch</strong></h3>    <p>每次调用then/catch,都会返回一个promise对象,这一点上我们通过使用===就可以判断出来每次promise对象其实都是不一样的</p>    <p>then和catch的错误处理区别</p>    <p>这点和上一点联合起来很容易理解</p>    <p>直接上图吧,来自于JavaScript Promise迷你书(中文版)</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/ce6c28f252d8eefde321b13b7eb20ec5.png"></p>    <p>在结合我们的代码吧</p>    <pre>  <code class="language-javascript">// <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);   }    </code></pre>    <p>onFullfilled中发生的错误,如在<1>里面throwError中的错误,是不会导致onRejected的执行(捕获异常)的,我们只能通过后面的catch方法才能捕获.</p>    <h3><strong>基本应用</strong></h3>    <p>不兼容方面</p>    <ol>     <li>不兼容就是用polyfill吧</li>     <li>关于IE8以及以下版本中,catch会由于在ES3中为保留字,导致identifier not found错误,对此我们可以通过["catch"]或者then(undefined,function(){})来进行catch,而某些类库中,采用了caught作为函数名来规避该问题.值得注意的是,有很多压缩工具中自带了.catch转["catch"]</li>    </ol>    <p>应用示例:</p>    <p>加载图片</p>    <pre>  <code class="language-javascript">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("图片加载失败");   })    </code></pre>    <p>Ajax操作</p>    <pre>  <code class="language-javascript">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);    </code></pre>    <p>回到最初吧,其实Promise对象优点还是在于规范的链式调用,可以清晰看出程序流程.并且对于错误还能定义统一的处理方法.</p>    <p> </p>    <p>来自:http://developer.51cto.com/art/201609/517558.htm</p>    <p> </p>