又有好些天沒有動筆了,這幾天一直在斷斷續續的學習Promise和generator,今天終於可以把着兩個玩意結合起來瞭解決異步問題了。今天我先把promise相關的用法和對異步的處理分享給你們。
老樣子,仍是先模擬一個Promise。html
//咳咳這樣就實現了嘛 let MyPromise = Promise;
開個玩笑,其實這兩天我也一直在看Promise的實現,可是仍是沒有怎麼理解。因此Promise的代碼實現我暫時先放一放,等我徹底理解再來新開一篇分享。這裏先給你們推薦幾篇我以爲比較好的Promise實現的博客,想要學習的小夥伴能夠先到那邊一睹爲快,固然等我更新了以後你們仍是要來給我文章點讚的哈。
完全理解Promise對象——用es5語法實現一個本身的Promise(上篇)這一篇文章用的es5的語法,對es6不是很熟悉的同窗能夠用這篇文章頂一下
Promise實現原理(附源碼)這一篇呢是用到了class的,因此須要你們對es6有所瞭解,也是一篇好文章es6
接下來我介紹一下Promise
最經常使用的幾個部分:編程
首先先介紹最簡單的只有一個Promise
對象的用法數組
//Promise()接收一個函數,而且在建立這個Promise對象的同時,接收的這個函數就會被馬上執行 var promise = new Promise(function (resolve, reject) { //resolve用來接收成功的返回,reject用來接收失敗的返回 setTimeout(function () { //這裏咱們生成一個隨機數,並在接下來根據這個隨機數的大小來判斷這個異步是否成功 let num = Math.random(); if (num > 0.8) { //接收失敗的緣由 console.log("reject") reject(num + "大於0.8,此次異步操做失敗了") } else { //接收成功的數據 console.log("resolve") resolve(num + "小於0.8,此次異步操做成功了") } }, 100) }); console.log("一個Promise對象生成了"); //Promise對象的.then()方法接收兩個回調,第一個爲成功回調,第二個爲失敗回調 //這兩個回調會在上面的resolve或者reject函數生效後被調用 promise.then(function (data) { //這個函數會在上面的resolve函數被調用後生效,這裏的data就是上面resolve()中接收的值 console.log(data) }, function (err) { ///這個函數會在上面的reject函數被調用後生效,這裏的err就是上面reject()中接收的值 console.error(err) }); console.log("promise的.then方法被調用了")
你們能夠按F12喚起控制檯,而後把這段代碼運行幾回。看看會有什麼結果;
多運行幾回之後,你們應該能夠看到這兩類結果:
其中的undefind是console.log("promise的.then方法被調用了")
這行代碼的返回,你們能夠不用關注。在這裏能夠看到不管是成功的結果仍是失敗的結果都是在定時器執行後再打印出來的。這種寫法能夠幫助咱們實現簡單的異步編程。promise
接下介紹多個Promise
對象同時使用的用法, 先介紹最多見的.then()鏈式調用的方法dom
//用來快速生成一個Promise對象,接收一個日誌列表,不論成功仍是失敗都會往日誌列表中添加一條日誌 function promise(log) { return new Promise(function (resolve, reject) { setTimeout(function () { log = log || []; //和上次的例子同樣,利用隨機數來隨機失敗和成功 let num = Math.random(); if (num > 0.5) { log.push(num + "大於0.5,此次異步操做失敗了"); reject(log) } else { log.push(num + "小於0.5,此次異步操做成功了"); resolve(log) } }, 100) }) }
.then()中返回了Promise對象的狀況異步
var promise1 = promise(); //promise1.then()方法會返回一個Promise對象 //若是咱們在.then()生效的那個 !!!回調方法!!! 中有返回一個Promise對象的話,該對象會被 !!!.then()方法!!! 返回 //先看返回了Promise對象的方式 promise1.then(function (data) { console.log(data); return promise(data) }, function (err) { console.error(err); return promise(err) }).then(function (data) { console.log(data) }, function (err) { console.error(err) });
這段代碼運行後一共會有四種結果:
兩次都成功
兩次都失敗
第一次失敗,第二次成功
第一次成功,第二次失敗
異步編程
經過這種方法咱們能夠用比較清晰的方式來書寫咱們的異步代碼。特別是多個異步操做嵌套的時候,能夠鏈式調用.then()來實現,這樣的代碼看起來邏輯更清晰;
剛剛看完了返回了Promise對象的場景,再來看看沒有返回Promise的場景函數
//若是咱們沒有返回Promise對象,.then()就會將咱們返回的東西包裝成一個Promise對象(沒有返回就至關於返回了undefined) //能夠等同於咱們寫了 return new Promise((resolve,reject)=>{resolve(/*原先的返回值*/)}) promise1.then(function (data) { console.log(data); return data; }, function (err) { console.error(err); return err; }).then(function (data) { console.log(data) }, function (err) { //這裏是永遠不會被觸發的,緣由是上一個.then() 返回的是new Promise((resolve,reject)=>{resolve(/*原先的返回值*/)}) //返回的Promise對象的reject方法永遠都不會被觸發,因此這個裏也就永遠都不會觸發了 console.error(err) });
講解都寫在註釋裏面了,接下里我就貼運行圖吧,這段代碼會運行出如下兩類結果:
學習
須要全部的請求都返回後才能夠執行某個動做
//改造promise,讓其能夠接收一個定時器等待時間參數 function promise(log, time) { return new Promise(function (resolve, reject) { setTimeout(function () { log = log || []; //和上次的例子同樣,利用隨機數來隨機失敗和成功 let num = Math.random(); if (num > 0.5) { log.push("等待時長" + time + "," + num + "大於0.5,此次異步操做失敗了"); console.error(log); reject(log) } else { log.push("等待時長" + time + "," + num + "小於0.5,此次異步操做成功了"); console.log(log); resolve(log) } }, time) }) } //Promise.all()能夠接收一個Promise對象的數組,返回一個Promise對象 //該Promise對象會在數組中全部Promise成功返回後執行成功回調,在任意一個Promise失敗後馬上執行失敗回調 var promise1 = promise(null, 10), promise2 = promise(null, 100), promise3 = Promise.all([promise1, promise2]); promise3.then((data) => { //這裏的data爲promise1,和promise2的返回值的數組 console.log("promise3", data) }, (err, err2) => { //報錯信息 console.error("promise3", err) });
這段代碼一共有四種可能的結果
若是兩次都成功的話
若是兩次都成的話,promise3會執行成功回調,而且回調中的data就是promise1和promise2返回值的數組(數組順序和.all()中的順序一致)
任意一個promise失敗的話,promise3會馬上執行失敗回調,而且回調中的err就是失敗的那個promise在reject中返回的值
文章寫到這裏,我認爲Promise經常使用的一些用法都已經講完了,更詳細的Promise的教程請參考 MDN中對promise的講解