徹底理解Javascript 中的 Promise
ES6原生提供了 Promise 對象。
到底是何方妖怪呢?打出來看看:
所謂 Promise,就是一個對象,用來傳遞異步操作的消息。它代表了某個未來才會知道結果的事件(通常是一個異步操作),并且這個事件提供統一的 API,可供進一步處理。
Promise 對象有以下兩個特點。
(1)對象的狀態不受外界影響。Promise 對象代表一個異步操作,有三種狀態: Pending(進行中)、Resolved(已完成,又稱 Fulfilled)和 Rejected(已失敗) 。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。這也是 Promise 這個名字的由來,它的英語意思就是「承諾」,表示其他手段無法改變。
(2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise 對象的狀態改變,只有兩種可能:從 Pending 變為 Resolved 和從 Pending 變為 Rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果。就算改變已經發生了,你再對 Promise 對象添加回調函數,也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。
有了 Promise 對象,就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。此外,Promise 對象提供統一的接口,使得控制異步操作更加容易。
Promise 也有一些缺點。首先,無法取消 Promise,一旦新建它就會立即執行,無法中途取消。其次,如果不設置回調函數,Promise 內部拋出的錯誤,不會反應到外部。第三,當處于 Pending 狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。
廢話不多說,直接上demo:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Promise 學習筆記</title>
<script type="text/javascript">
window.onload = function() {
function pms1() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('執行任務1');
resolve('執行任務1成功');
}, 2000);
});
}
function pms2() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('執行任務2');
resolve('執行任務2成功');
}, 2000);
});
}
function pms3() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('執行任務3');
resolve('執行任務3成功');
}, 2000);
});
}
pms1().then(function(data) {
console.log('第1個回調:' + data);
return pms2();
})
.then(function(data) {
console.log('第2個回調:' + data);
return pms3();
})
.then(function(data) {
console.log('第3個回調:' + data);
return '還沒完!該結束了吧!'
}).then(function(data) {
console.log(data);
});
}
</script>
</head>
<body>
</body>
</html>
怎么樣?是不是灰常簡單啊!
demo2:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.onload = function() {
function pms1() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
var num = Math.ceil(Math.random() * 10); //生成1-10的隨機數
if(num <= 5) {
resolve(num);
} else {
reject('數字太大了吧!');
}
}, 2000);
});
}
setInterval(function() {
pms1().then(function(data) { //小于等于5的
console.log(data);
}, function(data) { //大于的
console.log(data);
})
}, 1000);
}
</script>
</head>
<body>
</body>
</html>
Promise 構造函數接受一個函數作為參數,該函數的兩個參數分別是 resolve 方法和 reject 方法。
如果異步操作成功,則用 resolve 方法將 Promise 對象的狀態,從「未完成」變為「成功」(即從 pending 變為 resolved);
如果異步操作失敗,則用 reject 方法將 Promise 對象的狀態,從「未完成」變為「失敗」(即從 pending 變為 rejected)。
all的用法:
demo:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Promise 學習筆記</title>
<script type="text/javascript">
window.onload = function() {
function pms1() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('執行任務1');
resolve('執行任務1成功');
}, 2000);
});
}
function pms2() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('執行任務2');
resolve('執行任務2成功');
}, 2000);
});
}
function pms3() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('執行任務3');
resolve('執行任務3成功');
}, 2000);
});
}
Promise.all([pms1(), pms2(), pms3()]).then(function(data) {
console.log(data);
console.log({}.toString.call(data));
})
}
</script>
</head>
<body>
</body>
</html>
用Promise.all來執行,all接收一個數組參數,里面的值最終都算返回Promise對象。這樣,三個異步操作的并行執行的,等到它們都執行完后才會進到then里面。那么,三個異步操作返回的數據哪里去了呢?都在then里面呢,all會把所有異步操作的結果放進一個 數組 中傳給then,就是上面的results。
race的用法
all方法的效果實際上是「誰跑的慢,以誰為準執行回調」,那么相對的就有另一個方法「誰跑的快,以誰為準執行回調」,這就是race方法,這個詞本來就是賽跑的意思。race的用法與all一樣,我們把上面runAsync1的延時改為1秒來看一下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Promise 學習筆記</title>
<script type="text/javascript">
window.onload = function() {
function pms1() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('執行任務1');
resolve('執行任務1成功');
}, 1000);
});
}
function pms2() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('執行任務2');
resolve('執行任務2成功');
}, 2000);
});
}
function pms3() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('執行任務3');
resolve('執行任務3成功');
}, 3000);
});
}
Promise.race([pms1(), pms2(), pms3()]).then(function(data) {
console.log(data); //注意上面的延時時間
})
}
</script>
</head>
<body>
</body>
</html>
看到沒: 只有第一個執行了回調!
在then里面的回調開始執行時,runAsync2()和runAsync3()并沒有停止,仍舊再執行。于是再過1秒后,輸出了他們結束的標志。
這個race有什么用呢?使用場景還是很多的,比如我們可以用race給某個異步請求設置超時時間,并且在超時后執行相應的操作。
再來看看jquery里面的 $.Deferred:
jquery用$.Deferred實現了Promise規范,$.Deferred是個什么玩意呢?還是老方法,打印出來看看,先有個直觀印象:
var def = $.Deferred();
console.log(def);
輸出如下:
$.Deferred()返回一個對象,我們可以稱之為Deferred對象,上面掛著一些熟悉的方法如:done、fail、then等。jquery就是用這個Deferred對象來注冊異步操作的回調函數,修改并傳遞異步操作的狀態。
Deferred對象的基本用法如下,為了不與ajax混淆,我們依舊舉setTimeout的例子:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
<script type="text/javascript">
$(function() {
function runAsync() {
var def = $.Deferred();
setTimeout(function() {
console.log('執行完成');
def.resolve('隨便什么數據');
}, 2000);
return def;
}
runAsync().then(function(data) {
console.log(data)
});
})
</script>
</head>
<body>
</body>
</html>
在runAsync函數中,我們首先定義了一個def對象,然后進行一個延時操作,在2秒后調用def.resolve(),最后把def作為函數的返回。調用runAsync的時候將返回def對象,然后我們就可以.then來執行回調函數。
是不是感覺和ES6的Promise很像呢?
區別在何處一看便知。由于jquery的def對象本身就有resolve方法,所以我們在創建def對象的時候并未像ES6這樣傳入了一個函數參數,是空的。在后面可以直接def.resolve()這樣調用。
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
<script type="text/javascript">
$(function() {
function runAsync() {
var def = $.Deferred();
setTimeout(function() {
console.log('執行完成');
def.resolve('隨便什么數據');
}, 2000);
return def;
}
var pms=runAsync();
pms.then(function(data) {
console.log(data)
});
pms.resolve('我穿越了!')
})
</script>
</head>
<body>
</body>
</html>
這樣也有一個弊端,因為執行runAsync()可以拿到def對象,而def對象上又有resolve方法,那么豈不是可以在外部就修改def的狀態了?比如我把上面的代碼修改如下:
現象會如何呢?并不會在2秒后輸出“執行完成”,而是直接輸出“我穿越了”。因為我們在異步操作執行完成之前,沒等他自己resolve,就在外部給resolve了。這顯然是有風險的,比如你定義的一個異步操作并指定好回調函數,有可能被別人給提前結束掉,你的回調函數也就不能執行了。
怎么辦?jquery提供了一個promise方法,就在def對象上,他可以返回一個受限的Deferred對象,所謂受限就是沒有resolve、reject等方法,無法從外部來改變他的狀態,用法如下:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
<script type="text/javascript">
$(function() {
function runAsync() {
var def = $.Deferred();
setTimeout(function() {
console.log('執行完成');
def.resolve('隨便什么數據');
}, 2000);
return def.promise();
}
var pms=runAsync();
pms.then(function(data) {
console.log(data)
});
//pms.resolve('我穿越了!'); //這一句會報錯jquery-3.1.1.min.js:2 Uncaught TypeError: pms.resolve is not a function
})
</script>
</head>
<body>
</body>
</html>
then的鏈式調用
既然Deferred也是Promise規范的實現者,那么其他特性也必須是支持的。鏈式調用的用法如下:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
<script type="text/javascript">
$(function() {
function runAsync() {
var def = $.Deferred();
setTimeout(function() {
console.log('執行完成');
def.resolve('隨便什么數據');
}, 2000);
return def.promise();
}
var pms = runAsync();
pms.then(function(data) {
console.log('1:' + data);
return runAsync();
})
.then(function(data) {
console.log('2:' + data);
return runAsync();
})
.then(function(data) {
console.log('3:' + data);
});
//pms.resolve('我穿越了!'); //這一句會報錯jquery-3.1.1.min.js:2 Uncaught TypeError: pms.resolve is not a function
})
</script>
</head>
<body>
</body>
</html>
done與fail
我們知道,Promise規范中,then方法接受兩個參數,分別是執行完成和執行失敗的回調,而jquery中進行了增強,還可以接受第三個參數,就是在pending狀態時的回調,如下:
deferred.then( doneFilter [, failFilter ] [, progressFilter ] )
除此之外,jquery還增加了兩個語法糖方法,done和fail,分別用來指定執行完成和執行失敗的回調,也就是說這段代碼:
d.then(function(){
console.log('執行完成');
}, function(){
console.log('執行失敗');
});
與這段代碼是等價的:
d.done(function(){
console.log('執行完成');
})
.fail(function(){
console.log('執行失敗');
});
always的用法
jquery的Deferred對象上還有一個always方法,不論執行完成還是執行失敗,always都會執行,有點類似ajax中的complete。不贅述了。
$.when的用法
jquery中,還有一個$.when方法來實現Promise,與ES6中的all方法功能一樣,并行執行異步操作,在所有的異步操作執行完后才執行回調函數。不過$.when并沒有定義在$.Deferred中,看名字就知道,$.when,它是一個單獨的方法。與ES6的all的參數稍有區別,它接受的并不是數組,而是多個Deferred對象,如下:
$.when(runAsync(), runAsync2(), runAsync3())
.then(function(data1, data2, data3){
console.log('全部執行完成');
console.log(data1, data2, data3);
});
jquery中沒有像ES6中的race方法嗎?就是以跑的快的為準的那個方法。對的,jquery中沒有。
以上就是jquery中Deferred對象的常用方法了,還有一些其他的方法用的也不多,干脆就不記它了。接下來該說說ajax了。
ajax與Deferred的關系
jquery的ajax返回一個受限的Deferred對象,還記得受限的Deferred對象吧,也就是沒有resolve方法和reject方法,不能從外部改變狀態。想想也是,你發一個ajax請求,別人從其他地方給你取消掉了,也是受不了的。
既然是Deferred對象,那么我們上面講到的所有特性,ajax也都是可以用的。比如鏈式調用,連續發送多個請求:
req1 = function(){
return $.ajax(/*...*/);
}
req2 = function(){
return $.ajax(/*...*/);
}
req3 = function(){
return $.ajax(/*...*/);
}
req1().then(req2).then(req3).done(function(){
console.log('請求發送完畢');
});
明白了ajax返回對象的實質,那我們用起來就得心應手了。
success、error與complete
這三個方法或許是我們用的最多的,使用起來是這樣的:
$.ajax(/*...*/)
.success(function(){/*...*/})
.error(function(){/*...*/})
.complete(function(){/*...*/})
分別表示ajax請求成功、失敗、結束的回調。這三個方法與Deferred又是什么關系呢?其實就是語法糖,success對應done,error對應fail,complete對應always,就這樣,只是為了與ajax的參數名字上保持一致而已,更方便大家記憶,看一眼源碼:
deferred.promise( jqXHR ).complete = completeDeferred.add;
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail;
complete那一行那么寫,是為了減少重復代碼,其實就是把done和fail又調用一次,與always中的代碼一樣。deferred.promise( jqXHR )這句也能看出,ajax返回的是受限的Deferred對象。
jquery加了這么些個語法糖,雖然上手門檻更低了,但是卻造成了一定程度的混淆。一些人雖然這么寫了很久,卻一直不知道其中的原理,在面試的時候只能答出一些皮毛,這是很不好的。這也是我寫這篇文章的緣由。
看一個promise.js庫:
/*!
* Promise JavaScript Library v2.0.0
*/
;
(function(window) {
var _promise = function(thens) {
this.thens = thens || [];
this.state = "";
this._CONSTANT = {
any: "any",
number: "number",
resolved: "resolved",
rejected: "rejected",
pending: "pending"
};
};
_promise.prototype = {
resolve: function() {
if(this.state == this._CONSTANT.pending) {
this.state = this._CONSTANT.resolved;
return;
}
if(this.state !== "") return;
if(this.promiseArr) {
for(var i = 0, j = this.promiseArr.length; i < j; i++) {
this.promiseArr[i].resolveCount++;
}
if(this.promiseArr[0].action !== this._CONSTANT.any) {
if(this.resolveCount !== this.promiseArr.length) {
return;
}
} else {
if(this.resolveCount > 1) {
return;
}
}
}
this.state = this._CONSTANT.resolved;
if(!this.thens) return;
if(this.thens[0] && this.thens[0].finallyCB) this.thens[0].finallyCB.apply(null, arguments);
var t, n;
while(t = this.thens.shift()) {
if(typeof t === this._CONSTANT.number) {
var self = this;
setTimeout(function() {
var prms = new _promise(self.thens);
prms.resolve();
}, t);
break;
}
var doneFn = t.done,
action = t.action;
if(!doneFn) continue;
if(doneFn instanceof Array) {
var arr = [];
for(var i = 0, j = doneFn.length; i < j; i++) {
var df = doneFn[i];
if(df instanceof _promise) {
df.thens = this.thens;
arr.push(df);
} else {
var m = df.apply(null, arguments);
if(m instanceof _promise) {
m.thens = this.thens;
arr.push(m);
}
}
}
var l = arr.length;
if(l === 0) {
continue;
} else {
for(var i = 0; i < l; i++) {
arr[i].promiseArr = arr;
arr[i].action = action;
arr[i].resolveCount = 0;
}
break;
}
} else {
if(doneFn instanceof _promise) {
doneFn.thens = this.thens;
break;
} else {
n = doneFn.apply(null, arguments);
if(n instanceof _promise) {
n.thens = this.thens;
break;
}
}
continue;
}
}
},
reject: function() {
if(this.state !== "") return;
if(this.promiseArr && this.promiseArr[0].action === this._CONSTANT.any) {
if(this.promiseArr[this.promiseArr.length - 1] !== this) {
return;
}
}
this.state = this._CONSTANT.rejected;
if(!this.thens) return;
if(this.thens[0] && this.thens[0].finallyCB) this.thens[0].finallyCB.apply(null, arguments);
var t, n;
while(t = this.thens.shift()) {
if(typeof t === this._CONSTANT.number) {
var self = this;
setTimeout(function() {
var prms = new _promise(self.thens);
prms.resolve();
}, t);
break;
}
if(t.fail) {
n = t.fail.apply(null, arguments);
if(n instanceof _promise) {
n.thens = this.thens;
break;
}
continue;
}
break;
}
},
notify: function() {
var t = this.thens[0];
t.progress.apply(null, arguments);
},
then: function(done, fail, progress) {
this.thens.push({
done: done,
fail: fail,
progress: progress
});
return this;
},
any: function(done, fail, progress) {
this.thens.push({
done: done,
fail: fail,
progress: progress,
action: this._CONSTANT.any
});
return this;
},
done: function(done) {
if(this.thens.length === 0 || this.thens[this.thens.length - 1].done) {
this.thens.push({
done: done
});
} else {
this.thens[this.thens.length - 1].done = done;
}
return this;
},
fail: function(fail) {
if(this.thens.length === 0 || this.thens[this.thens.length - 1].fail) {
this.thens.push({
fail: fail
});
} else {
this.thens[this.thens.length - 1].fail = fail;
}
return this;
},
progress: function(progress) {
if(this.thens.length === 0 || this.thens[this.thens.length - 1].progress) {
this.thens.push({
progress: progress
});
} else {
this.thens[this.thens.length - 1].progress = progress;
}
return this;
},
ensure: function(finallyCB) {
if(this.thens.length === 0 || this.thens[this.thens.length - 1].finallyCB) {
this.thens.push({
finallyCB: finallyCB
});
} else {
this.thens[this.thens.length - 1].finallyCB = finallyCB;
}
return this;
},
always: function(alwaysCB, progress) {
this.thens.push({
done: alwaysCB,
fail: alwaysCB,
progress: progress
});
return this;
},
wait: function(ms) {
this.thens.push(~~ms);
return this;
}
}
var Promise = function(parameter) {
var prms = new _promise();
if(parameter) {
if(arguments.length > 1) {
prms.thens[0] = {};
prms.thens[0].done = [];
prms.thens[0].done.push.apply(prms.thens[0].done, arguments);
setTimeout(function() {
prms.resolve();
}, 1)
} else {
prms = parameter();
if(prms instanceof _promise) return prms;
}
}
return prms;
};
Promise.when = function() {
var prms = new _promise();
prms.thens[0] = {};
prms.thens[0].done = [];
prms.thens[0].done.push.apply(prms.thens[0].done, arguments);
setTimeout(function() {
prms.resolve();
}, 1)
return prms;
};
Promise.any = function() {
var prms = new _promise();
prms.thens[0] = {};
prms.thens[0].action = prms._CONSTANT.any;
prms.thens[0].done = [];
prms.thens[0].done.push.apply(prms.thens[0].done, arguments);
setTimeout(function() {
prms.resolve();
}, 1)
return prms;
};
Promise.timeout = function(promise, ms) {
setTimeout(function() {
promise.reject();
}, ms);
return promise;
}
Promise.gtTime = function(promise, ms) {
promise.state = promise._CONSTANT.pending;
setTimeout(function() {
if(promise.state == promise._CONSTANT.resolved) {
promise.state = "";
promise.resolve();
}
promise.state = "";
}, ms);
return promise;
}
if(typeof module === "object" && module && typeof module.exports === "object") {
module.exports = Promise;
} else {
window.Promise = Promise;
if(typeof define === "function" && define.amd) {
define("promise", [], function() {
return Promise;
});
}
}
}(window));
promise.js提供了done和resolve方法,done負責注冊成功的回調函數,resolve負責觸發。
function cb() {
alert('success')
}
var prms = Promise()
prms.done(cb)
setTimeout(function() {
prms.resolve()
}, 3000)
在3秒之后,瀏覽器將alert “success”。
當然你也可以通過prms.resolve(“xxx”)傳遞參數給cb函數使用,如:
function cb(num) {
alert(num)
}
var prms = Promise()
prms.done(cb)
setTimeout(function() {
prms.resolve(1)
}, 3000)
在3秒之后,瀏覽器將alert “1”。
fail/reject
fail函數負責注冊失敗的回調函數,reject負責觸發。如:
function cb() {
alert('fail')
}
var prms = Promise()
prms.fail(cb)
setTimeout(function () {
prms.reject()
}, 3000)
progress/notify
progress函數負責注冊處理中進度的回調函數,notify負責觸法。如:
function cb() {
alert('progress')
}
var prms = Promise()
prms.progress(cb)
setInterval(function() {
prms.notify()
}, 2000)
每隔兩秒瀏覽器會彈出一個progress。
chain
function cb1() {
alert('success')
}
function cb2() {
alert('fail')
}
function cb3() {
alert('progress')
}
var prms = Promise();
prms.done(cb1).fail(cb2).progress(cb3)
setTimeout(function () {
prms.resolve()
//prms.reject()
//prms.notify()
}, 3000)
then
function fn1() {
alert('success')
}
function fn2() {
alert('fail')
}
function fn3() {
alert('progress')
}
var prms = Promise()
prms.then(fn1, fn2, fn3)
prms.resolve()
prms.reject()
prms.notify()
當然也支持prms.then().then().then()……….
當then的第一個參數為一個數組的時候,要等所有task都完成:
f1().then([f2_1, f2_2]).then(f3)
如上面的代碼:
f1執行完后,同時執行f2_1和f2_2,當f2_1和f2_2 全部 都執行完成才會執行f3。
any
f1().any([f2_1, f2_2]).then(f3)
f1執行完后,同時執行f2_1和f2_2,當f2_1和f2_2中的 任意一個 執行完成才會執行f3。
always
var prms = Promise()
prms.always(function () {
alert(2)
})
setTimeout(function () {
// prms.resolve()
prms.reject()
}, 3000)
always(fn)等同于then(fn,fn),也等同于done(fn).fail(fn)
wait
function f10() {
var promise = Promise();
setTimeout(function () {
console.log(10);
promise.resolve();
}, 4500)
return promise;
}
function f11() {
var promise = Promise();
setTimeout(function () {
console.log(11);
promise.resolve();
}, 1500)
return promise;
}
f11().wait(5000).then(f10) //execute f11 then wait 5000ms then execute f10
ensure
ensure方法類似try…catch..finally中的finally,不管task成功失敗都會執行。
Promise.when
Promise.when(f1(), f2()).then(f3).then(f4)
function f1() {
var promise = Promise();
setTimeout(function () {
console.log(1);
promise.resolve("from f1");
}, 1500)
return promise;
}
function f2() {
var promise = Promise();
setTimeout(function () {
console.log(2);
promise.resolve();
}, 5500)
return promise;
}
function f3() {
var promise = Promise();
setTimeout(function () {
console.log(3);
promise.resolve();
}, 1500)
return promise;
}
function f4() {
var promise = Promise();
setTimeout(function () {
console.log(4);
promise.resolve();
}, 1500)
return promise;
}
上面promise.when的等同簡略寫法也可以是:Promise(f1(),f2()).then….
Promise.any
Promise.any的使用和when一樣,when的意義是等所有task都完成再執行后面的task,而any的意義是任何一個task完成就開始執行后面的task。
Promise.timeout
Promise.timeout(f1(), 2000).then(f2, function () {
alert("timeout");
}).wait(5000).then(f3);
function f1() {
var promise = Promise();
setTimeout(function () {
console.log(1);
promise.resolve("from f1");
}, 1500)
return promise;
}
function f2() {
var promise = Promise();
setTimeout(function () {
console.log(2);
promise.resolve();
}, 1500)
return promise;
}
function f3() {
var promise = Promise();
setTimeout(function () {
console.log(3);
promise.resolve();
}, 1500)
return promise;
}
with wind.js
<script src="wind-all-0.7.3.js"></script>
<script src="promise.js"></script>
<script>
Wind.Promise.create = function (fn) {
var prms = Promise();
fn(prms.resolve, prms.reject);
return prms;
}
var testAsync = eval(Wind.compile("promise", function () {
for (var i = 0; i < 3; i++) { //loop 3 times
var aa = $await(f1());
alert(aa); //alert “from f1”
$await(f2().wait(3000)); //execute f2 then wait 3000ms
$await(f3());
}
}));
testAsync();
function f1() {
var promise = Promise();
setTimeout(function () {
console.log(1);
promise.resolve("from f1");
}, 2500)
return promise;
}
function f2() {
var promise = Promise();
setTimeout(function () {
console.log(2);
promise.resolve();
}, 1500)
return promise;
}
function f3() {
var promise = Promise();
setTimeout(function () {
console.log(3);
promise.resolve();
}, 1500)
return promise;
}
</script>
That’s all.Have Fun!
來自:http://www.cnblogs.com/libin-1/p/5947602.html