异步与同步相比,最难以掌控的就是异步的任务会何时完成和完成以后的回调问题,javascript
难以掌控的触发状态,让你本身写的代码当时还能够读懂,可是过几天、半个月以后若是不从新盘一边逻辑,你哪知道哪一个内容会先执行,借用这么一个例子java
listen( "click", function handler(evt){ setTimeout( function request(){ ajax( "http://some.url.1", function response(text){ if (text == "hello") { handler(); } else if (text == "world") { request(); } } ); }, 500) ; } ); doSomething(); 复制代码
很难以理解这种地狱式的回调(回调地狱)会对可读性有多么大的摧毁。面试
首先 执行listern()ajax
其次 doSomething()数组
500ms(或者更远)后执行ajax()promise
ajax完成后markdown
若是text === hello 执行handler()dom
若是text === world 执行request()异步
难受吗???async
在你不知道的javascript一书中,对于回调的信任问题作了阐述 当你使用第三方的库的方法处理回调时颇有可能遇到如下信任内容:
怎么解决???? 这种信任问题该怎么办?
当你把一件事情交给别人去作(可能立刻就能完成的也多是须要一段时间的)这我的在任务完成或者失败后都会给你一个回应,这样的人你是否是特别放心的把事情交给他,他没回应你那么他是正在办事、回应你了就是成功了或者失败了。
Promise的实例有三个状态,Pending(进行中)、Resolved(已完成)、Rejected(已拒绝)。当你把一件事情交给promise时,它的状态就是Pending,任务完成了状态就变成了Resolved、没有完成失败了就变成了Rejected。
言归正传:写一个简单的promise
let promise = new Promise((resolve,reject)=>{ // 接收一个callback。参数是成功函数与失败函数 setTimeout(()=>{ let num = parseInt(Math.random()*100); // 若是数字大于50就调用成功的函数,而且将状态变成Resolved if(num > 50){ resolve(num); }else{ // 不然就调用失败的函数,将状态变成Rejected reject(num) } },10000) }) 复制代码
当Promise执行的内容符合你预期的成功条件的话,就调用resolve函数,失败就调用reject函数,这两个函数的参数会被promise捕捉到。能够在以后的回调中使用。
建立一个承诺咱们已经作完了,那么如何使用承诺后的结果呢?
promise.then(res=>{ console.log(res); //在构造函数中若是你执行力resolve函数就会到这一步 },err=>{ // 执行了reject函数会到这一步 console.log(err); }) 复制代码
then方法接收两个函数,第一个是承诺成功(状态为resolved)的回调函数,一个承诺失败(状态为rejected)的回调函数。
then方法的返回值不是一个promise对象就会被包装成一个promise对象,因此then方法支持链式调用。
promise.then(res=>{ return 42}).then(res=>{console.log(res)}) // 打印出42 复制代码
then方法的链式调用能够帮咱们串行的解决一些逻辑,当咱们平时书写有顺序的异步时间,好比
ajax('first'); ajax('second'); ajax('third'); 须要按顺序来执行怎么办? ajax('first').success(function(res){ ajax('second').success(function(res){ ajax('third').success(function(res){ //串行完毕能够执行你想要的内容了 }); }) }) 多么美丽而又让人望而却步的三角形啊!! 复制代码
若是使用then的链式调用呢?
let promise = new Promise((resolve,reject)=>{ ajax('first').success(function(res){ resolve(res); }) }) promise.then(res=>{ return new Promise((resovle,reject)=>{ ajax('second').success(function(res){ resolve(res) }) }) }).then(res=>{ return new Promise((resovle,reject)=>{ ajax('second').success(function(res){ resolve(res) }) }) }).then(res=>{ // 串行完毕你要作的xxx能够开始了 }) 复制代码
并且每次执行resolve的时候,均可以把每次ajax的回调数据进行传递到最后。清晰简单明了。
说完串行了,那么并行怎么办??? 当有多个异步事件,之间并没有联系并且没有前后顺序,只须要所有完成就能够开始工做了。
串行会把每个异步事件的等待时间进行一个相加,明显会对完成进行一个阻塞。那么并行的话该怎么肯定所有完成呢?
Promise.all 接收一个数组,数组的每一项都是一个promise对象。当数组中全部的promise的状态都达到resolved的时候,Promise.all的状态就会变成resolved,若是有一个状态变成了rejected,那么Promise.all的状态就会变成rejected(任意一个失败就算是失败),这就能够解决咱们并行的问题。调用then方法时的结果成功的时候是回调函数的参数也是一个数组,按顺序保存着每个promise对象resolve执行时的值。
let promise1 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(1); },10000) }); let promise2 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(2); },9000) }); let promise3 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(3); },11000) }); Promise.all([promise1,promise2,promise3]).then(res=>{ console.log(res); //[1,2,3] 证实与哪一个promise的状态先变成resolved无关 }) let promise1 = new Promise((resolve,reject)=>{ setTimeout(()=>{ reject(1); },10000) }); let promise2 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(2); },9000) }); let promise3 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(3); },11000) }); let promiseAll =Promise.all([promise1,promise2,promise3]); promiseAll.then(res=>{ console.log(res); },err=>{ console.log(err) }) 复制代码
Promise.race 竞速模式 也是接受一个每一项都是promise的数组。可是与all不一样的是,第一个promise对象状态变成resolved时自身的状态变成了resolved,第一个promise变成rejected自身状态就会变成rejected。第一个变成resolved的promsie的值就会被使用。
let promise1 = new Promise((resolve,reject)=>{ setTimeout(()=>{ reject(1); },10000) }); let promise2 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(2); },9000) }); let promise3 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(3); },11000) }); Promise.race([promise1,promise2,promise3]).then(res=>{ console.log(res); //打印出2 为何不打印出1呢?由于promise2先完成了其他的就忽略来 },rej=>{ console.log('rejected'); console.log(rej)}; ) // 你们能够尝试本身改变时间进行测试 复制代码
Promsie.race还有一个很重要的实际用处就是,有时候咱们要去作一件事,可是超过三秒钟左右咱们就不作了那怎么办? 这个时候可使用Promise.race方法
Promise.race([promise1,timeOutPromise(3000)]).then(res=>{}) // timeOutPromise延时3s左右 因为是用setTimeout来实现的并不必定准确3s(通常主线程在开发中不会阻塞3s以上的因此不会有太大问题) 复制代码
这就是我对于Promise的一些基本理解。
很难受的一件事 白天辛苦写的1736个字的内容莫名其妙的被我删掉了。。。。。内容都去哪了??? 很蓝瘦。。。 因此晚上又从新梳理了一遍。
下一期的内容是针对于网上常见的Promise的自我实现进行一个分析,
总之一句话抓住Promise的承诺思想,就能够很好的去编写promise的代码。
async 与await将会在下期或者下下期进行讲解。(很抱歉,想一口气讲完的可是内容太多,我也须要慢慢梳理争取给你们一个高质量的文章,)