前言
個人博客:http://zhangsunyucong.top
這篇文章主要講兩個內容,一是,初步認識Promise,二是,Async模塊和Async/Await的使用
什麼是Promise
Promise表示一個異步操作的最終結果。一個Promise對象有一個then方法,then方法中返回一個Promise。
相關的概念
- promise是一個包含了兼容promise規範then方法的對象或函數,
- thenable 是一個包含了then方法的對象或函數。
- value 是任何Javascript值。 (包括 undefined, thenable, promise等).
- exception 是由throw表達式拋出來的值。
- reason 是一個用於描述Promise被拒絕原因的值。
Promise的狀態
Promise有三種狀態:pending, fulfilled 或 rejected。pending是等待執行狀態,fulfilled是成功執行狀態,rejected是失敗執行狀態。
Promise只能從pending到fulfilled或者從pending到rejected狀態,當狀態發生改變時,promise.then(onFulfilled, onRejected)方法將被調用。Promise可以使用resolve或者reject將value或者reason作爲下一個Promise的第一個回調參數。
來個簡單的Promise基本用法:
var promise = new Promise(function(resolve, reject){
//do something
if(success){
resolve(value);
} else {
reject(value);
}
});
promise.then(function(value){
//成功時調用
}, function(value){
//失敗時調用
});
上面的代碼只是表示Promise用法的流程.
使用Promise/A+規範實現以下幾個功能
- 上一步的結果可以作爲下一步的參數
- 出現異常時,能夠捕獲到異常
- 可以在每一步進行流程控制
Promise的具體知識,可以參考這裏
下面介紹Async模塊和ES7的Async/Await的使用
Async模塊
Async模塊的github地址:https://github.com/caolan/async/
配置好node的環境後(具體過程,自己百度),安裝Async模塊
npm install –save async
Async模塊提供了很多關於集合,流程控制,工具方法,這裏只體驗幾個常見的流程控制方法:series,parallel,waterfall,auto。其他方法的用法,可以查看官方文檔:文檔地址
series的使用
series(tasks, callback)
tasks可以是數組或者對象
series是串行執行tasks中的任務,如果有一個任務執行返回了錯誤信息,則不再繼續執行後面未執行的任務,並將結果以數組或者對象的形式傳給callback。具體結果的格式由你定義tasks時使用的是數組還是對象。
async.series([
function (callback) {
setTimeout(function () {
console.log("one");
callback(null, 'one');
}, 300);
},
function (callback) {
setTimeout(function () {
console.log("two");
callback(null, 'two');
}, 200);
},
function (callback) {
setTimeout(function () {
console.log("three");
callback(null, 'three');
}, 100);
}
], function (err, results) {
console.log(err);
console.log(results);
});
運行結果:
one
two
three
null
[ ‘one’, ‘two’, ‘three’ ]
當tasks是對象:
async.series({
one: function (callback) {
setTimeout(function () {
console.log("one");
callback(null, 'one');
}, 300);
},
two: function (callback) {
setTimeout(function () {
console.log("two");
callback(null, 'two');
}, 200);
},
three: function (callback) {
setTimeout(function () {
console.log("three");
callback(null, 'three');
}, 100);
}
}, function (err, results) {
if(err) {
console.log("異常結束" + '結果爲:' + results);
return;
}
console.log(results);
});
運行結果:
one
two
three
{ one: ‘one’, two: ‘two’, three: ‘three’ }
上面代碼中,從上到下的函數開始執行時間是逐漸減小的,而運行結果的輸出順序是one,two,three,說明series是串行執行任務的。
將第二個任務的代碼改爲以下的樣子:
function (callback) {
console.log("two");
setTimeout(function () {
callback("errMsg", 'two');
}, 200);
}
運行的結果爲:
one
two
errMsg
[ ‘one’, ‘two’ ]
可以看到,當第二個任務返回了錯誤信息,則不會再繼續執行後面未執行的任務
parallel的使用
parallel(tasks, callback)
tasks可以是一個數組或者對象
parallel是並行執行多個任務,如果有一個任務執行返回了一個錯誤信息,則不再繼續執行後面未執行的任務,並將結果以數組或者對象的形式傳給callback。
async.parallel([
function (callback) {
setTimeout(function() {
console.log('one');
callback(null, 'one');
}, 500);
},
function (callback) {
setTimeout(function() {
console.log('two');
callback(null, 'two');
}, 200);
},
function (callback) {
setTimeout(function() {
console.log('three');
callback(null, 'three');
}, 100);
}
], function (err, results) {
console.log(err);
console.log(results);
});
運行結果爲:
three
two
one
null
[ ‘one’, ‘two’, ‘three’ ]
結果中的輸出順序是three,two,one,說明parallel是並行執行任務的。
同樣,將第二個任務的代碼改爲:(數組定義tasks)
function (callback) {
setTimeout(function() {
console.log('two');
callback("errMsg", 'two');
}, 200);
},
運行的結果爲:
three
two
errMsg
[ <1 empty item>, ‘two’, ‘three’ ]
one
將第二個任務代碼改爲:(數組定義tasks)
function (callback) {
setTimeout(function() {
console.log('two');
callback("errMsg", 'two');
}, 200);
},
將第三個任務代碼改爲:(數組定義tasks)
function (callback) {
setTimeout(function() {
console.log('three');
callback(null, 'three');
}, 200);
}
也就是,第三個的開始執行時間改成和出現錯誤信息的第二個任務的時間一樣。
運行的結果爲:
two
errMsg
[ <1 empty item>, ‘two’ ]
three
one
從結果中可以看出,當前面執行的未完成的任務會佔一個位置,而後面未完成的任務不會佔數組的位置。
parallelLimit(tasks, limit, callback)
parallelLimit和parallel差不多,區別是它可以指定同時並行執行任務的最大數量。
async.parallelLimit({
one: function (callback) {
setTimeout(function() {
console.log('one');
callback(null, 'one');
}, 200);
},
two: function (callback) {
setTimeout(function() {
console.log('two');
callback(error, 'two');
}, 200);
},
three: function (callback) {
setTimeout(function() {
console.log('three');
callback(null, 'three');
}, 100);
}
}, 2, function (err, results) {
console.log(err);
console.log(results);
});
運行的結果爲:
one
two
errMsg
{ one: ‘one’, two: ‘two’ }
three
如果是tasks是數組時,運行的結果是:
two
errMsg
[ <1 empty item>, ‘two’ ]
one
由於同時並行執行任務的最大數量是2,由於第二個任務產生錯誤信息,第三個任務還沒開始執行。另外如果要取最後回調結果中的值,對象定義tasks可能會更好。
waterfall的使用
waterfall(tasks, callback)
tasks只能是數組類型
waterfall會串行執行tasks中的任務,前一個任務的結果可以作爲下一個任務的參數。
async.waterfall([
function (callback) {
console.log("one");
setTimeout(function() {
callback(null, 'one', 'two');
}, 200);
},
function (arg1, arg2, callback) {
console.log("two" + '參數:' + "arg1是" + arg1 + "arg2是" + arg2);
setTimeout(function() {
callback(null, 'three');
}, 200);
},
function (arg3, callback) {
console.log("three" + '參數:' + "arg3是" + arg3);
setTimeout(function() {
callback(null, 'done', 'done1');
}, 200);
}
], function (err, results) {
if(err) {
console.log("異常結束" + '結果爲:' + results);
return;
}
console.log(results);
});
運行的結果是:
one
two參數:arg1是onearg2是two
three參數:arg3是three
done
輸出的結果的順序是one,two, three,是串行執行的。前一個任務的結果可以作爲下一個任務的參數。
注意一下,代碼中控制檯輸出的one,two,three代碼是移到了定時器的外面。
auto的使用
auto(tasks, concurrencyopt, callback)
auto可以串行和並行執行任務,可以定義任務之間的依賴關係。沒有依賴關係的任務會儘可能快的開始並行執行,串行是由於任務的依賴關係而實現的。concurrencyopt指定的是並行執行任務的最大數量。tasks只能是對象類型。
async.auto({
task1: function(callback) {
setTimeout(function() {
console.log('task1');
callback(null, 'data', 'data1');
}, 200);
},
task2: function(callback) {
setTimeout(function () {
console.log('task2');
callback(null, 'data2');
}, 100)
},
task3: ['task1', 'task2', function(results, callback) {
console.log('task3', JSON.stringify(results));
setTimeout(function () {
console.log('task3');
callback(null, 'data3');
}, 200);
}],
task4: ['task3', function(results, callback) {
console.log('task4', JSON.stringify(results));
setTimeout(function () {
console.log('task4');
callback(null, {'task2':results.task2, 'task4':'data4'});
}, 100);
}]
}, function(err, results) {
console.log('err = ', err);
console.log('results = ', results);
});
運行的結果是:
task2
task1
task3 {“task2”:”data2”,”task1”:[“data”,”data1”]}
task3
task4 {“task2”:”data2”,”task1”:[“data”,”data1”],”task3”:”data3”}
task4
err = null
results = { task2: ‘data2’,
task1: [ ‘data’, ‘data1’ ],
task3: ‘data3’,
task4: { task2: ‘data2’, task4: ‘data4’ } }
task1和task2是不依賴於任何其他任務的,它們會儘可能的開始,而且由於它們是並行執行的,task2的開始時間較短,所以task2比task1先開始。task3依賴於task1和task2,所以task3等到task1和task2執行完畢後再執行。task4依賴task3,所以task4要等到task3執行完畢後再執行。
ES7的Async/Await
主要看它們的用法
var task1 = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("result");
}, 1000);
});
};
var excTask1 = async function () {
console.log("start");
console.log(await task1());
console.log("end");
};
function awaitDemo() {
excTask1();
}
連續點擊運行四次,運行的結果爲:
start
start
start
start
result
end
result
end
result
end
result
end
async代表是一個async函數,await只能用在async函數中,await等待一個Promise的返回,直到Promise返回了纔會繼續執行await後面的代碼。這裏的Promise利用setTimeout模擬異步任務。
從輸出結果中可以看出,每次執行都是到await時,就停止等待Promise的返回,後再繼續執行await後面的代碼。