摘要:這時(shí),第二個(gè)方法指定的回調(diào)函數(shù),就會等待這個(gè)新的對象狀態(tài)發(fā)生變化。
1.概述
javascript是單線程語言(單線程/多線程、阻塞/非阻塞、同步、異步)參考此文章,所有的任務(wù)都是按順序執(zhí)行的,但是對于很耗時(shí)的操作采用異步的方式(前一個(gè)任務(wù)結(jié)束的時(shí)候,不是執(zhí)行下一個(gè)任務(wù),而是執(zhí)行回調(diào)函數(shù),后一個(gè)任務(wù)則是不等前一個(gè)任務(wù)結(jié)束就執(zhí)行)參考此文章,js中異步編程的四種方法:回調(diào)函數(shù)、事件監(jiān)聽、發(fā)布/訂閱、Promise對象,這里討論promise的用法,promise是es6增加的內(nèi)容,使得在異步編程中不用過多的嵌套回調(diào)函數(shù),讓異步操作變得更加簡單
2.Promise介紹 2.1 Promise構(gòu)造函數(shù)Promise構(gòu)造函數(shù)接收一個(gè)函數(shù)作為參數(shù),此函數(shù)又有兩個(gè)參數(shù)分別為resolve和reject,這兩個(gè)參數(shù)也是函數(shù)
const promise = new Promise(function(resolve, reject) { // 異步操作的代碼 if(success) { return resolve(data); // data為異步操作成功返回的數(shù)據(jù) } else { return reject(error); //data為失敗時(shí)返回的數(shù)據(jù) } })2.2 resolve和reject
promise對象類似于一個(gè)容器(也可以說是一個(gè)狀態(tài)機(jī)),里面包含著異步操作,異步操作會有兩種結(jié)果:成功或失敗。當(dāng)異步操作成功就會將pending(執(zhí)行中狀態(tài))轉(zhuǎn)為fulfilled(成功狀態(tài))同時(shí)觸發(fā)resolve函數(shù),用來將操作成功后得到的結(jié)果傳遞出去;當(dāng)異步操作失敗就會將pending(執(zhí)行中狀態(tài))轉(zhuǎn)為reject(拒絕狀態(tài))同時(shí)觸發(fā)reject函數(shù),用來將操作失敗后報(bào)出的錯(cuò)誤傳遞出去
const promise = new Promise(function(resolve, reject) { // 異步操作的代碼 if(success) { return resolve(data); // data為異步操作成功返回的數(shù)據(jù) } else { return reject(error); //data為失敗時(shí)返回的數(shù)據(jù) } })
我們來看下面代碼:
function fn1() { return new Promise(function(resolve, reject){ setTimeout(() => { console.log("fn1") },1000) }) } function fn2() { return new Promise(function(resolve, reject){ setTimeout(() => { console.log("fn2") },2000) }) } fn1().then(fn2)
輸出為:
fn1
fn2函數(shù)不執(zhí)行,這個(gè)時(shí)候我們需要調(diào)用resolve函數(shù)以便執(zhí)行then()方法中的回調(diào)函數(shù)fn2
function fn1() { return new Promise(function(resolve, reject){ setTimeout(() => { console.log("fn1") resolve("fn1") },1000) }) }
輸出為:
fn1
fn2
如果我們在fn1中調(diào)用reject函數(shù)時(shí)會出現(xiàn)什么情況呢?
function fn1() { return new Promise(function(resolve, reject){ setTimeout(() => { console.log("fn1") // resolve("fn1") reject("錯(cuò)誤"+"fn1") },1000) }) } fn1().then(fn2).then((data) => { console.log(data) })
輸出為:
提示錯(cuò)誤未捕獲,所以需要在then()方法中添加第二個(gè)回到函數(shù)來處理出錯(cuò)信息
fn1().then(fn2).then((data) => { console.log(data) }, (err) => { console.log(err) })
輸出為:
當(dāng)promise實(shí)例生成以后,后面跟then方法,其的第一個(gè)回調(diào)函數(shù)來處理resolve函數(shù)傳遞的數(shù)據(jù),第二個(gè)回調(diào)函數(shù)來處理reject函數(shù)傳遞的數(shù)據(jù),以上的流程用代碼展示如下
promise .then(function(data){ //拿到返回的數(shù)據(jù)之后做一些處理 console.log(data) }, function(error) { //返回失敗時(shí)做一些處理 console.log(error) })2.3.1 then()的返回值
then()方式是Promise實(shí)例的方法,此then方法定義在原型對象(Promise.prototype)上,then()方法的返回值是一個(gè)新的Promise實(shí)例(不是原來那個(gè)Promise,原來那個(gè)Promise已經(jīng)承諾過)所以我們可以采用鏈?zhǔn)降膶懛?/p>
var p1 = new Promise( (resolve, reject) => { setTimeout(() => resolve("p1"), 10); }); p1.then( ret => { console.log(ret); return "then1"; }).then( ret => { console.log(ret); return "then2"; }).then( ret => { console.log(ret); });
執(zhí)行順序:
p1>then1>then2
從第二個(gè)then()方法開始,它們的resolve中的參數(shù)就是前一個(gè)then()中的resolve的return語句的返回值
采用鏈?zhǔn)降膖hen,可以指定一組按照次序調(diào)用的回調(diào)函數(shù)。這時(shí),前一個(gè)回調(diào)函數(shù),有可能返回的還是一個(gè)Promise對象(即有異步操作),這時(shí)后一個(gè)回調(diào)函數(shù),就會等待該P(yáng)romise對象的狀態(tài)發(fā)生變化,才會被調(diào)用
getJSON("/post/1.json").then(function(post) { return getJSON(post.commentURL);}).then(function funcA(comments) { console.log("resolved: ", comments);}, function funcB(err){ console.log("rejected: ", err);})
上面代碼中,第一個(gè)then方法指定的回調(diào)函數(shù),返回的是另一個(gè)Promise對象。這時(shí),第二個(gè)then方法指定的回調(diào)函數(shù),就會等待這個(gè)新的Promise對象狀態(tài)發(fā)生變化。如果變?yōu)閞esolved,就調(diào)用funcA,如果狀態(tài)變?yōu)閞ejected,就調(diào)用funcB。
如果采用箭頭函數(shù),上面的代碼可以寫得更簡潔
getJSON("/post/1.json").then( post => getJSON(post.commentURL)).then( comments => console.log("resolved: ", comments), err => console.log("rejected: ", err));
promise鏈?zhǔn)綄懛ㄈ缦拢?/p>
function fn1() { return new Promise(function(resolve, reject){ setTimeout(() => { console.log("fn1") resolve("fn1") },1000) }) } function fn2() { return new Promise(function(resolve, reject){ setTimeout(() => { console.log("fn2") resolve("fn2") },2000) }) } function fn3() { return new Promise(function(resolve, reject){ setTimeout(() => { console.log("fn3") resolve("fn3") },3000) }) } function fn4() { return new Promise(function(resolve, reject){ setTimeout(() => { console.log("fn4") resolve("fn4") },4000) }) } fn1().then(fn2).then(fn3).then((data) => { console.log(data) }, (err) => { console.log(err) })
依次輸出為:fn1>fn2>fn3
同時(shí)我們還可以更改執(zhí)行的先后順序
function fn1() { return new Promise(function(resolve, reject){ setTimeout(() => { console.log("fn1") reject(false) },1000) }) } function fn2() { return new Promise(function(resolve, reject){ setTimeout(() => { console.log("fn2") resolve("fn2") },2000) }) } function fn3() { return new Promise(function(resolve, reject){ setTimeout(() => { console.log("fn3") resolve("fn3") },3000) }) } function fn4() { return new Promise(function(resolve, reject){ setTimeout(() => { console.log("fn4") resolve("fn4") },4000) }) } fn1().then(fn2).then(fn3).then((data) => { console.log(data) }, (err) => { if(err == false){ fn3().then(fn4) } })
輸出為:fn1>fn3>fn4
2.4 catch()方法我們在開發(fā)時(shí)傾向于用catch()方法來處理異常,而不是在then()方法里寫入第二個(gè)回調(diào)函數(shù),這種寫法類似于.then(null, rejection)
promise .then(function(data){ //拿到返回的數(shù)據(jù)之后做一些處理 console.log(data) }) .catch(function(error) { //返回失敗時(shí)做一些處理 console.log(error) }
為什么要采用這么catch()方法呢?我們來看一個(gè)例子:
const promise = new Promise((resolve,reject) => { console.log(1) resolve("成功") }) promise .then((data) => { console.log(data) console.log(a) }, (err) => { console.log(err) })
輸出為:
1
成功
但是沒有捕捉到回調(diào)函數(shù)里a未定義
這個(gè)時(shí)候我們來該寫以上代碼
1
成功
ReferenceError: a is not defined
Promise對象的Error對象具有冒泡性質(zhì),會一直向后傳遞,直到被捕獲為止。也就是說,錯(cuò)誤總是會被下一個(gè)catch語句捕獲
var p = new Promise( (resolve, reject) => { setTimeout(() => resolve("p1"), 10); }); p.then( ret => { console.log(ret); throw new Error("then1"); return "then1"; }).then( ret => { console.log(ret); throw new Error("then2"); return "then2"; }).catch( err => { // 可以捕抓到前面的出現(xiàn)的錯(cuò)誤。 console.log(err.toString()); });
輸出為:
p1
Error: then1
既然catch()是.then(null, rejection)的別名,那么catch()就會返回一個(gè)Promise對象,因此在后面還可以接著調(diào)用then方法
var p = new Promise((resolve, reject) => { resolve(x + 2); }); p.then( () => { console.log("nothing"); }).catch( err => { console.log(err.toString()); return "catch"; }).then( ret => { console.log(ret); });
輸出為:
ReferenceError: x is not defined
catch
當(dāng)出錯(cuò)時(shí),catch會先處理之前的錯(cuò)誤,然后通過return語句,將值繼續(xù)傳遞給后一個(gè)then方法中,如果沒有報(bào)錯(cuò),則跳過catch,示例如下:
var p = new Promise((resolve, reject) => { resolve("p"); }); p.then( ret => { console.log(ret); return "then1"; }).catch( err => { console.log(err.toString()); return "catch"; }).then( ret => { console.log(ret); });3. promise用法解析 3.1 用Promise實(shí)現(xiàn)ajax操作
const getJSON = function(url) { const promise = new Promise(function(resolve, reject){ const handler = function() { if (this.readyState !== 4) { return; } if (this.status === 200) { resolve(this.response); } else { reject(new Error(this.statusText)); } }; const client = new XMLHttpRequest(); client.open("GET", url); client.onreadystatechange = handler; client.responseType = "json"; client.setRequestHeader("Accept", "application/json"); client.send(); }); return promise; }; getJSON("/posts.json").then(function(json) { console.log("Contents: " + json); }, function(error) { console.error("出錯(cuò)了", error); });3.2 promise和ajax方法結(jié)合
var http = { get: function(url) { var promise = new Promise(function(resolve, reject) { $.ajax({ url: url, method: "get", success: function(data) { resolve(data); }, error: function(xhr, statusText) { reject(statusText); } }); }); return promise; } }; http.get("data.php").then(function(data) { document.write(data); }, function(err) { document.write(err); });3.3 用promise實(shí)現(xiàn)異步加載圖片的例子
function loadImageAsync(url) { return new Promise(function(resolve, reject) { const image = new Image(); image.onload = function() { resolve(image); }; image.onerror = function() { reject(new Error("Could not load image at " + url)); }; image.src = url; }); } var loadImage1 = loadImageAsync(url); loadImage1.then(function success() { console.log("success"); }, function fail() { console.log("fail"); });3.4 promise和axios方法結(jié)合
function fetch(url, params) { return new Promise((resolve, reject) => { axios.post(url, params) .then(response => { resolve(response.data); }, error => { reject(error); }) .catch(error => { reject(error) }) }) } function lineStatus(params) { return fetch("/ProductionLine/GetStatus", params) } function statisticsData(params) { return fetch("/ProductionLine/GetWeightStatistics", params) } lineStatus(this.lineId) .then((result) => { this.deviceStatus.run = result.TotleMoveMotor this.deviceStatus.stop = result.TotleStopMotor this.deviceStatus.lost = result.TotleLoseMotor this.deviceStatus.alarm = result.TotleAlarmMotor this.ProductionStatus = result.ProductionStatus console.log(result) }) .catch((error) => { console.log("瓦特了...(;′⌒`)") }) statisticsData(this.lineId) .then((result) => { this.outputData.totalOutput = result.MainConveyorModel.OutPut this.outputData.instantWeight = result.MainConveyorModel.InstantWeight this.outputData.runningTime = result.MainConveyorModel.RunningTime this.outputData.motorLoad = result.MainConveyorModel.MotorLoad // console.log(result) }) .catch((error) => { console.log("瓦特了...(;′⌒`)") })
以上是Promise在開發(fā)中常見的用法,參考了以下幾篇文章,特此感謝作者
Promise 對象[阮一峰]
[es6系列]學(xué)習(xí)Promise
阮一峰的ES6---Promise對象
對Promise中的resolve,reject,catch的理解
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/107121.html
摘要:概述是異步編程的一種解決方案,很好的解決了傳統(tǒng)異步編程中的回調(diào)地獄問題。語法中闡述,有三種狀態(tài),分別是進(jìn)行中已完成已失敗。方法使用要使用方法我們首先要創(chuàng)建實(shí)例,也就是說我們要一個(gè)對象。 1. Promise概述 promise是異步編程的一種解決方案,很好的解決了傳統(tǒng)異步編程中的回調(diào)地獄問題。同時(shí)我們可以把promise可以理解為一個(gè)容器,這個(gè)容器里面存放著一些未來才會結(jié)束的事件(通常...
摘要:有了對象,就可以將異步操作以同步操作的流程表達(dá)出來,避免了層層嵌套的回調(diào)函數(shù)。此外,對象提供統(tǒng)一的接口,使得控制異步操作更加容易。它的作用是為實(shí)例添加狀態(tài)改變時(shí)的回調(diào)函數(shù)。這時(shí),第二個(gè)方法指定的回調(diào)函數(shù),就會等待這個(gè)新的對象狀態(tài)發(fā)生變化。 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案(回調(diào)函數(shù)和事件)更合理和更強(qiáng)大。它由社區(qū)最早出和實(shí)現(xiàn),ES6 將其寫進(jìn)了語言標(biāo)準(zhǔn),統(tǒng)一了...
摘要:在服務(wù)工作線程中,延長事件的壽命從而阻止瀏覽器在事件中的異步操作完成之前終止服務(wù)工作線程。在事件中,它延遲將視為已激活的,直到傳遞的被成功地。這主要用于確保任何功能事件不會被分派到對象,直到它升級數(shù)據(jù)庫模式并刪除過期的緩存條目。 看了很多介紹Service Worker的,看得都挺模糊的,所以決定自己寫一篇文件整理一下思路。 一、Service Worker API 名詞區(qū)分 1、Se...
摘要:就是每次傳入的函數(shù)最后是的任務(wù)之后,開始執(zhí)行,可以看到此時(shí)會批量執(zhí)行中的函數(shù),而且還給這些中回調(diào)函數(shù)放入了一個(gè)這個(gè)很顯眼的函數(shù)之中,表示這些回調(diào)函數(shù)是在微任務(wù)中執(zhí)行的。下一模塊會對此微任務(wù)中的插隊(duì)行為進(jìn)行詳解。 有關(guān)Eventloop+Promise的面試題大約分以下幾個(gè)版本——得心應(yīng)手版、游刃有余版、爐火純青版、登峰造極版和究極變態(tài)版。假設(shè)小伙伴們戰(zhàn)到最后一題,以后遇到此類問題,都是...
閱讀 3067·2021-11-02 14:40
閱讀 869·2019-08-30 15:53
閱讀 1298·2019-08-30 15:53
閱讀 3286·2019-08-30 13:53
閱讀 3337·2019-08-29 12:50
閱讀 1162·2019-08-26 13:49
閱讀 1892·2019-08-26 12:20
閱讀 3694·2019-08-26 11:33