如果您的瀏覽器支持JavaScript 1.7或更高版本(在撰寫本文時,我認爲只有Gecko瀏覽器可以),那麼您可以利用生成器來完成此操作。讓我們先來讓你的connect
功能異步(和更簡單的用於測試):
function connectAsync(callback) {
// Pretend we always succeed after a second.
// You could use some other asynchronous code instead.
setTimeout(callback, 1000, true);
}
現在換你調用代碼到一個函數。 (必須在功能上)
function main() {
console.log("Connecting...");
if(!(yield connect())) {
console.log("Failed to connect.");
yield; return;
}
console.log("Connected.");
yield;
}
請注意所有的yield
到處。這是魔術的一部分。當我們在每個函數退出點之前調用connect
和yield
時,我們需要yield
。我們需要定義connect
。您可能需要一堆您可能想要同步的異步函數,因此我們來創建一個使函數同步的函數。
function synchronize(async) {
return function synchronous() {
return {func: async, args: arguments};
};
}
然後,我們可以用它創建connectAsync
connect
:
var connect = synchronize(connectAsync);
現在我們需要運行所有的這種神奇的功能。那就是:
function run(sync) {
var args = Array.prototype.slice.call(arguments);
var runCallback = args.length ? args[args.length - 1] : null;
if(args.length) {
args.splice(args.length - 1, 1);
}
var generator = sync.apply(window, args);
runInternal(generator.next());
function runInternal(value) {
if(typeof value === 'undefined') {
if(runCallback) {
return runCallback();
}else{
return;
}
}
function callback(result) {
return runInternal(generator.send(result));
}
var args = Array.prototype.slice.call(value.args);
args.push(callback);
value.func.apply(window, args);
}
}
現在你可以用這個神奇的運行main
功能:
run(main);
我要指出,這是不再可能main
返回一個值。 run
可以採用第二個參數:在同步功能完成時要調用的回調函數。要將參數傳遞main
(比方說,1
,2
和3
),你會這樣稱呼它:
run(main, 1, 2, 3, callback);
如果你不想一個回調,通過null
或undefined
。
要嘗試了這一點,你必須設置script
標籤的type
到text/javascript; version=1.7
。 JavaScript 1.7添加了新的關鍵字(如yield
),因此它是向後不兼容的,因此必須有一些方法才能將自己與舊代碼區分開來。
有關發電機的更多信息,請參閱this page on MDN。有關協程的更多信息,請參閱the article on Wikipedia。
綜上所述,這是不實用的,因爲JavaScript 1.7的有限支持。此外,看到這類代碼並不常見,因此可能難以理解和維護。 我建議只使用異步樣式,如Deisss's answer中所示。不過,它是可能要做到這一點。
歡迎來到**異步**的美妙世界!你不能那樣做。 – SLaks
爲什麼我不能評論評論? –
這不是想法!沒有什麼是不可能的! –