摘要:不兼容問題,本文不予以處理,出門左轉,找谷哥。如果中的回調函數拋出一個錯誤,那么返回的將會成為拒絕狀態,并且將拋出的錯誤作為拒絕狀態的回調函數的參數值。
Promise與async
0. 基本用法主要內容:
promise基本實現原理
promise 使用中難點(鏈式調用,API基本上返回都是一個新Promise,及參數傳遞)
promise 對異常處理
參考:
? 30分鐘,讓你徹底明白Promise原理
? 阮一峰ES6入門
? JavaScript Promise:簡介
基本的promise使用
1. 兼容性查看caniuse
查兼容性 基本上 主流瀏覽器支持沒有問題。
IE不兼容 問題,本文不予以處理,出門左轉,找谷哥。具體查看 babel,或者 自己實現一個Promise
2. ajax XMLHttpRequest封裝//get 請求封裝 function get(url) { // Return a new promise. return new Promise(function(resolve, reject) { // Do the usual XHR stuff var req = new XMLHttpRequest(); req.open("GET", url); req.onload = function() { // This is called even on 404 etc // so check the status if (req.status == 200) { // Resolve the promise with the response text resolve(req.response); } else { // Otherwise reject with the status text // which will hopefully be a meaningful error reject(Error(req.statusText)); } }; // Handle network errors req.onerror = function() { reject(Error("Network Error")); }; // Make the request req.send(); }); }1. Promse API
Promise API 分為 :MDN
靜態方法
prototype上方法
Promise.prototype.then() 來分析
首先來看看 Promise.prototype.then()返回一個Promise,但Promise內部有返回值,且 返回值,可以是個值,也可能就是一個新Promise
*具體規則如下:* - *如果then中的回調函數返回一個值,那么then返回的Promise將會成為接受狀態,并且將返回的值作為接受狀態的回調函數的參數值。* - *如果then中的回調函數拋出一個錯誤,那么then返回的Promise將會成為拒絕狀態,并且將拋出的錯誤作為拒絕狀態的回調函數的參數值。* - *如果then中的回調函數返回一個已經是接受狀態的Promise,那么then返回的Promise也會成為接受狀態,并且將那個Promise的接受狀態的回調函數的參數值作為該被返回的Promise的接受狀態回調函數的參數值。* - *如果then中的回調函數返回一個已經是拒絕狀態的Promise,那么then返回的Promise也會成為拒絕狀態,并且將那個Promise的拒絕狀態的回調函數的參數值作為該被返回的Promise的拒絕狀態回調函數的參數值。* - *如果then中的回調函數返回一個未定狀態(pending)的Promise,那么then返回Promise的狀態也是未定的,并且它的終態與那個Promise的終態相同;同時,它變為終態時調用的回調函數參數與那個Promise變為終態時的回調函數的參數是相同的。*
上面是官方規則,神馬,具體白話就是 核心是 返回參數及返回promise的狀態
參考:MDN
是不是 覺得很暈,沒關系,可以先看 下一節,看完后,再回過來看具體的說明2. Prmise 鏈式調用
1. 值傳遞問題鏈式調用
1. 核心就是 then catch 等方法返回一個Promise 2. 鏈式 調用數據傳遞(注意)
簡單例子
//正常狀態 const promise1 = new Promise((resolve, reject) => { resolve("0000")// }) promise1.then(result => { console.log(result) //0000 return "1111";//類似于 return Promise.resolve("1111"); 參數是data,promise 狀態時 resolve }).then(data => { console.log(data) // 1111 })
一個實際的例子:(拿來大神的例子JavaScript Promise:簡介)
get("story.json").then(function(response) { console.log("Success!", response); })
//這里的 response 是 JSON,但是我們當前收到的是其純文本。也可以設置XMLHttpRequest.responseType =json get("story.json").then(function(response) { return JSON.parse(response); }).then(function(response) { console.log("Yey JSON!", response); })
//由于 JSON.parse() 采用單一參數并返回改變的值,因此我們可以將其簡化為: get("story.json").then(JSON.parse).then(function(response) { console.log("Yey JSON!", response); })
function getJSON(url) { return get(url).then(JSON.parse); } //getJSON() 仍返回一個 promise,該 promise 獲取 URL 后將 response 解析為 JSON。2. 異步操作隊列
上面至今是return 值 ,直接調用 下一下then就OK了。
但如果return Promise,則?
Promise.resolve(111).then(function(d){ console.log(d); return Promise.resolve(d+111);//返回promise }).then(function(d2){ console.log(d2); }) // 111,2223. 基本實現原理
主要是 如何自己實現一個簡單的Promise
//極簡實現 function Promise(fn) { var value = null, callbacks = []; //callbacks為數組,因為可能同時有很多個回調 this.then = function (onFulfilled) { callbacks.push(onFulfilled); }; function resolve(value) { callbacks.forEach(function (callback) { callback(value); }); } fn(resolve); }4. finnaly 實現
Promise.prototype.finally = function (callback) { let P = this.constructor; return this.then( value => P.resolve(callback()).then(() => value), reason => P.resolve(callback()).then(() => { throw reason }) ); };5. 異常處理
1. Promise 異常處理基本套路異常分類:
同步異常
異步異常 無法try-catch 得到
多層Promise嵌套,獲異常取具體的一個promise異常,而不是全部
基本處理異常中,有兩種方案then(undefined, func) 與catch()
但then(undefined, func) 與catch()不同,具體參見代碼方案3
//方案1 使用 Promise.prototype.catch()來catch const promise1 = new Promise((resolve, reject) => { reject("no")// }) promise1.then(result => { console.log(result) // 永遠不會執行 }).catch(error => { console.log(error) // no })
//方案2 使用 Promise.prototype.then()中第二個參數 來處理 const promise1 = new Promise((resolve, reject) => { reject("no")// }) promise1.then(result => { console.log(result) // 永遠不會執行 },error => { console.log(error) // no })
//方案2 (方案1 方案2 對比) var promise2 = new Promise((resolve, reject) => { resolve("yes")// }) promise2.then(result => { throw new Error("then"); console.log(result) },error => { console.log("1111",error) // no }).catch(error=>{ console.log("2222",error)// 最終 err在此處被捕獲,而不是 then 中 })2. 異常不同分類
Promise可能遇到的異常種類
//1.異常 reject() const promise1 = new Promise((resolve, reject) => { reject("no")// }) promise1.then(result => { console.log(result) // 永遠不會執行 }).catch(error => { console.log(error) // no })
//2.異常 顯示throw const promise1 = new Promise((resolve, reject) => { throw Error("no") }) promise1.then(result => { console.log(result) // 永遠不會執行 }).catch(error => { console.log(error) // })
//3.執行異常 const promise1 = new Promise((resolve, reject) => { aaaa; }) promise1.then(result => { console.log(result) // 永遠不會執行 }).catch(error => { console.log(error) // })3. 異常鏈式調用
asyncThing1().then(function() { return asyncThing2(); }).then(function() { return asyncThing3(); }).catch(function(err) { return asyncRecovery1(); }).then(function() { return asyncThing4(); }, function(err) { return asyncRecovery2(); }).catch(function(err) { console.log("Don"t worry about it"); }).then(function() { console.log("All done!"); })
上述代碼的流程圖形式:
// promise鏈式調用,catch住異常后,后面就不會處理異常了 Promise.reject().then(()=>{ console.log(2222); },(err)=>{ console.log(333,err) return err}) .catch((err)=>{ console.log(1111,err); }) //333 undefined ,沒有打印 1111
//如果 在鏈式調用中,then 第二個參數 catch住了異常,沒有return Promise.reject()則后續鏈式調用返回rosolve狀態pormise Promise.reject() .then(()=>{ console.log(111); },(err)=>{ console.log(111,err) //reject return err; }).then((data)=>{ console.log(222,data);//resolve 執行 },(err)=>{ console.log(222,err); //未執行 }) //4444 沒有執行 11114. 異常丟失
很多情況下,promise無法捕獲異常
場景1 macrotask 隊列中拋出異常:
//場景1 //永遠不要在 macrotask 隊列中拋出異常,因為 macrotask 隊列脫離了運行上下文環境,異常無法被當前作用域捕獲。 function fetch(callback) { return new Promise((resolve, reject) => { setTimeout(() => { throw Error("用戶不存在") }) }) } fetch().then(result => { console.log("請求處理", result) // 永遠不會執行 }).catch(error => { console.log("請求處理異常", error) // 永遠不會執行 }) // 程序崩潰 // Uncaught Error: 用戶不存在 /* 參考 作者:黃子毅 鏈接:https://www.jianshu.com/p/78dfb38ac3d7 來源:簡書 簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權并注明出處。 */
//解決場景1 怎么解決,因為setTimeout 是macrotask任務,執行上下文完全不同 /** 如何解決? 調用reject */ function fetch() { return new Promise((resolve, reject) => { setTimeout(() => { reject("收斂一些") }) }) } fetch().then((resolve, reject) => { console.log("resolve"); }).catch(error => { console.log("捕獲異常", error) // 捕獲異常 收斂一些 })
場景二 Promise 狀態只能改變一次
//異常丟失 const promise2 = new Promise((resolve, reject) => { reject("no") console.log("reject after") throw Error("no") //異常丟失 }) promise1.then(result => { console.log(result) // 永遠不會執行 }).catch(error => { console.log("err",error) // no }).catch(error => { console.log("err2",error) // 也無法捕獲異常 })6.async
基本語法
function timeout(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } async function asyncPrint(value, ms) { await timeout(ms); console.log(value); return value; //類似 return Promise.resolve(value) } //async 返回一個promise asyncPrint("hello world", 50).then(function(d){ console.log("then",d); }); /** 打印 hello world then hello world */
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98156.html
摘要:形式非必須,也非必須調用把用函數表示在調用的時候用函數代碼更加同步化三是什么異步操作的終極解決方案寫法四總結不管用還是用還是用,都保證你寫的的返回值是一個對象 一、promise入門 1. Promise對象是什么 回調函數的另一種原生實現,比之前回調函數的寫法機構清晰,功能強大, 2.以前回調這么寫 function a(fn){ let h = 1; setTime...
摘要:而之后,我們得到的是一個是一個對象,我們可以使用語句定義回調函數,函數的內容呢,則是將讀取到的返回給并繼續讓從斷點處執行。 在上一篇中我們梳理了koa當中中間件的洋蔥模型執行原理,并實現了一個可以讓洋蔥模型自動跑起來的流程管理函數。這一篇,我們再來研究一下koa當中異步回調同步化寫法的原理,同樣的,我們也會實現一個管理函數,是的我們能夠通過同步化的寫法來寫異步回調函數。 1. 回調金字...
摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:方法完成回調注冊模式下,對象通過方法調用,注冊完成態和失敗態的回調函數。這些回調函數組成一個回調隊列,處理的值。調用實例的方法,能使注冊的回調隊列中的回調函數依次執行。 之前寫了一篇關于ES6原生Promise的文章。近期又讀樸靈的《深入淺出Node》,里面介紹了一個Promise/Deferred模式。 Promise是解決異步問題的利器。它其實是一種模式。Promise有三種狀態,...
摘要:異步編程是每個使用編程的人都會遇到的問題,無論是前端的請求,或是的各種異步。本文就來總結一下常見的四種處理異步編程的方法。利用一種鏈式調用的方法來組織異步代碼,可以將原來以回調函數形式調用的代碼改為鏈式調用。 異步編程是每個使用 JavaScript 編程的人都會遇到的問題,無論是前端的 ajax 請求,或是 node 的各種異步 API。本文就來總結一下常見的四種處理異步編程的方法。...
閱讀 1402·2021-10-11 10:59
閱讀 3103·2019-08-30 15:54
閱讀 2724·2019-08-30 13:19
閱讀 2455·2019-08-30 13:02
閱讀 2371·2019-08-30 10:57
閱讀 3346·2019-08-29 15:40
閱讀 980·2019-08-29 15:39
閱讀 2299·2019-08-29 12:40