javascript是單線程語言(單線程/多線程、阻塞/非阻塞、同步、異步)參考此文章,全部的任務都是按順序執行的,可是對於很耗時的操做採用異步的方式(前一個任務結束的時候,不是執行下一個任務,而是執行回調函數,後一個任務則是不等前一個任務結束就執行)參考此文章,js中異步編程的四種方法:回調函數、事件監聽、發佈/訂閱、Promise對象,這裏討論promise的用法,promise是es6增長的內容,使得在異步編程中不用過多的嵌套回調函數,讓異步操做變得更加簡單javascript
Promise構造函數接收一個函數做爲參數,此函數又有兩個參數分別爲resolve和reject,這兩個參數也是函數php
const promise = new Promise(function(resolve, reject) {
// 異步操做的代碼
if(success) {
return resolve(data); // data爲異步操做成功返回的數據
} else {
return reject(error); //data爲失敗時返回的數據
}
})
複製代碼
promise對象相似於一個容器(也能夠說是一個狀態機),裏面包含着異步操做,異步操做會有兩種結果:成功或失敗。當異步操做成功就會將pending(執行中狀態)轉爲fulfilled(成功狀態)同時觸發resolve函數,用來將操做成功後獲得的結果傳遞出去;當異步操做失敗就會將pending(執行中狀態)轉爲reject(拒絕狀態)同時觸發reject函數,用來將操做失敗後報出的錯誤傳遞出去java
const promise = new Promise(function(resolve, reject) {
// 異步操做的代碼
if(success) {
return resolve(data); // data爲異步操做成功返回的數據
} else {
return reject(error); //data爲失敗時返回的數據
}
})
複製代碼
咱們來看下面代碼:ios
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函數不執行,這個時候咱們須要調用resolve函數以便執行then()方法中的回調函數fn2es6
function fn1() {
return new Promise(function(resolve, reject){
setTimeout(() => {
console.log('fn1')
resolve('fn1')
},1000)
})
}
複製代碼
輸出爲:
fn1
fn2
若是咱們在fn1中調用reject函數時會出現什麼狀況呢?ajax
function fn1() {
return new Promise(function(resolve, reject){
setTimeout(() => {
console.log('fn1')
// resolve('fn1')
reject('錯誤'+'fn1')
},1000)
})
}
fn1().then(fn2).then((data) => {
console.log(data)
})
複製代碼
輸出爲:編程
fn1().then(fn2).then((data) => {
console.log(data)
}, (err) => {
console.log(err)
})
複製代碼
輸出爲:json
當promise實例生成之後,後面跟then方法,其的第一個回調函數來處理resolve函數傳遞的數據,第二個回調函數來處理reject函數傳遞的數據,以上的流程用代碼展現以下axios
promise
.then(function(data){
//拿到返回的數據以後作一些處理
console.log(data)
}, function(error) {
//返回失敗時作一些處理
console.log(error)
})
複製代碼
then()方式是Promise實例的方法,此then方法定義在原型對象(Promise.prototype)上,then()方法的返回值是一個新的Promise實例(不是原來那個Promise,原來那個Promise已經承諾過)因此咱們能夠採用鏈式的寫法segmentfault
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);
});
複製代碼
執行順序:
p1>then1>then2
從第二個then()方法開始,它們的resolve中的參數就是前一個then()中的resolve的return語句的返回值 採用鏈式的then,能夠指定一組按照次序調用的回調函數。這時,前一個回調函數,有可能返回的仍是一個Promise對象(即有異步操做),這時後一個回調函數,就會等待該Promise對象的狀態發生變化,纔會被調用
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);})
複製代碼
上面代碼中,第一個then方法指定的回調函數,返回的是另外一個Promise對象。這時,第二個then方法指定的回調函數,就會等待這個新的Promise對象狀態發生變化。若是變爲resolved,就調用funcA,若是狀態變爲rejected,就調用funcB。 若是採用箭頭函數,上面的代碼能夠寫得更簡潔
getJSON("/post/1.json").then(
post => getJSON(post.commentURL)).then(
comments => console.log("resolved: ", comments),
err => console.log("rejected: ", err));
複製代碼
promise鏈式寫法以下:
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
同時咱們還能夠更改執行的前後順序
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
咱們在開發時傾向於用catch()方法來處理異常,而不是在then()方法裏寫入第二個回調函數,這種寫法相似於.then(null, rejection)
promise
.then(function(data){
//拿到返回的數據以後作一些處理
console.log(data)
})
.catch(function(error) {
//返回失敗時作一些處理
console.log(error)
}
複製代碼
爲何要採用這麼catch()方法呢?咱們來看一個例子:
const promise = new Promise((resolve,reject) => {
console.log(1)
resolve('成功')
})
promise
.then((data) => {
console.log(data)
console.log(a)
}, (err) => {
console.log(err)
})
複製代碼
輸出爲:
1
成功
可是沒有捕捉到回調函數裏a未定義 這個時候咱們來該寫以上代碼
1
成功
ReferenceError: a is not defined
Promise對象的Error對象具備冒泡性質,會一直向後傳遞,直到被捕獲爲止。也就是說,錯誤老是會被下一個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 => {
// 能夠捕抓到前面的出現的錯誤。
console.log(err.toString());
});
複製代碼
輸出爲:
p1
Error: then1
既然catch()是.then(null, rejection)的別名,那麼catch()就會返回一個Promise對象,所以在後面還能夠接着調用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
當出錯時,catch會先處理以前的錯誤,而後經過return語句,將值繼續傳遞給後一個then方法中,若是沒有報錯,則跳過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);
});
複製代碼
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('出錯了', error);
});
複製代碼
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);
});
複製代碼
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");
});
複製代碼
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在開發中常見的用法,參考瞭如下幾篇文章,特此感謝做者