在javascript開發過程中,我們不可避免的會遇到一些非同步編程的情景,無論是前端的ajax請求還是,node的各種非同步api,下文是在工作學習過程中總結的關於javascript非同步編程集中常見方式用法的總結 回調函數 使用回調函數是最常見的一種形式 //jQuery ajax $.get('t ...
在javascript開發過程中,我們不可避免的會遇到一些非同步編程的情景,無論是前端的ajax請求還是,node的各種非同步api,下文是在工作學習過程中總結的關於javascript非同步編程集中常見方式用法的總結
回調函數
使用回調函數是最常見的一種形式
//jQuery ajax
$.get('test.php',res=>{
//數據處理
});
//node非同步讀取文件
let fs=require('fs');
fs.read('file/path',(error,data)=>{
//數據處理
});
回調函數就是定義函數的時候,將另外一個函數(回調函數)作為參數傳入,在非同步操作執行完成後就會執行該回調函數,從而可以保證在回調函數中的操作可以在非同步執行完成之後執行。回調函數的缺點是當需要執行多個非同步操作時,需要將多個回調函數嵌套在一起,組成代碼結構上的混亂,可讀性較差,被稱為“回調地獄”。
func1(data1,()=>{
func2(data2,()=>{
func3(data3,()=>{
//業務邏輯
});
});
});
Promise
Promise以一種鏈式調用的方法來組織非同步代碼,可以將原來以回調函數形式調用的非同步操作,改寫為promise鏈式調用
//jQuery ajax promise
$('test.html').then(res=>{
//業務邏輯
}).then(res=>{
//業務邏輯
});
我們還可以利用ES6的Promise構造函數,自定義Promise
let resultA=new Promise((resolve,reject)=>{
let flag=Math.random()<0.5;
setTimeout(()=>{
if(flag){
resolve({
result:true,
msg:'ok'
});
}
else{
reject({
result:false,
msg:'error'
});
}
},0);
});
resultA.then(res=>{
console.log(res.msg);
return Promise.resolve('I am from this first promise');
}).catch(err=>{
console.log(err.msg);
}).then(res=>{
console.log(res);
});
在最新版本的node(node 8.0+)環境里,還可以利用util.promisify方法將回調函數形式的函數直接轉換為Promise形式。
let util = require('util');
let fs = require('fs');
let readFilePromise = util.promisify(fs.readFile);
readFilePromise('demo.js','utf-8').then((data)=>{
console.log(data);
});
Generators
node的著名開發者TJ利用ES6的新特性生成器開發了一個非同步控制控制工具co,Generators生成器,藉助co可以將非同步代碼的寫法寫成類似同步代碼的形式。
let util = require('util');
let fs = require('fs');
let co=require('co');
let readFilePromise = util.promisify(fs.readFile);
co(function *(){
let baz = yield readFilePromise('baz.js','utf-8');
console.log(baz);
let foo = yield readFilePromise('foo.js','utf-8');
console.log(foo);
});
可以看出Generator的優點顯而易見,它可以使非同步代碼寫的非常清晰,可讀性很高,缺點使依賴第三方庫才能使用該特性。
Async/Await
node7.6以上的版本引入了一個es7的新特性 Async/Await,專門用來進行非同步控制,下麵先看一簡單的個例子
let delay = new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('test');
resolve('msg from promise');
});
});
let baz = async ()=>{
let res = await delay;
console.log(res);//'msg from promise'
};
baz();
首先我們需要使用async關鍵字定義一個包含非同步代碼執行的函數,在promise形式你的非同步執行函數前面使用await關鍵字,就可以將非同步寫成同步的操作形式。
相比Generators生成器,由於Async/Await使原生的非同步控制方案,所以比較推薦使用的。