1 2 3 4 5 6 7 8 9
| setTimeout(function() { console.log("拉数据"); setTimeout(function() { console.log("做这个那个,再发数据"); setTimeout(function() { console.log("数据发送成功,恭喜充值成功游戏时间 +1s!"); },3000) },2000) },1000)
|
噢,亲爱的,你一定去过地狱,是吗?
欢迎来到异步世界
当世界没有异步运算的时候,程序顺序执行,简单明了。有一天来了一个异步运算——拉数据
1 2 3 4 5 6 7
| var data = 0; function getData() { setTimeout(function (){ data = 1; console.log("数据拉取成功"); },1000); }
|
拉完数据自然要处理。
1 2 3 4
| function handleData(){ data += 1; console.log("处理数据完成"); }
|
按照顺序逻辑编写代码
1 2 3 4
| getData(); handleData();
|
天呐,居然先处理了数据才拉取数据。这是自然的。因为计算是异步的,所以不得不把所有跟数据有关的函数移到异步函数内部。
1 2 3 4 5 6 7 8 9 10 11 12 13
| var data = 0; function getData() { setTimeout(function (){ data = 1; console.log("数据拉取成功"); handleData(); },1000); }
function handleData(){ data += 1; console.log("处理数据完成"); }
|
运行时候的代码
拉玩还不算,还得发数据。做完一次人肉 CPS 变换后代码变成这样
1 2 3 4 5 6 7 8 9 10 11
| function getData(){ setTimeout(function() { console.log("拉数据"); setTimeout(function() { console.log("做这个那个,再发数据"); setTimeout(function() { console.log("数据发送成功,恭喜充值成功游戏时间 +1s!"); },3000) },2000) },1000) }
|
什么?你觉得代码还好?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| setTimeout(function(){ setTimeout(function(){ setTimeout(function(){ setTimeout(function(){ setTimeout(function(){ setTimeout(function(){ setTimeout(function(){ setTimeout(function(){ setTimeout(function(){ setTimeout(function(){ setTimeout(function(){ console.log("终于做完了") },1000) },1000) },1000) },1000) },1000) },1000) },1000) },1000) },1000) },1000) },1000)
|
欢迎来到回调地狱。
未来的承诺
很长一段时间不少人都写着这种代码,终于 ES 6 美好的承诺 Promise 来临。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| function getData(callback) { setTimeout(function (){ var data = 0; console.log("数据拉取成功"); callback(data); },1000); console.log("拉取中……") }
function handleData(data) { return new Promise(function(resolve){ console.log("处理中……"); setTimeout(function(){ data += 1; console.log("处理数据完成"); resolve(data); },2000); }); }
function sendData(data) { return new Promise(function(resolve){ console.log("发送中……"); setTimeout(function(){ console.log("数据发送成功"); resolve(data); },3000); }); }
function showSucess(data){ console.log("恭喜充值成功游戏时间 +" + data + "s!"); }
|
这么运行
1 2 3 4 5
| var async = new Promise(function(resolve){ getData(resolve) });
async.then(handleData).then(sendData).then(showSucess);
|
除了写法上更直观外,还可以使用 .catch()
捕获异常。
还可以使用 .all()
当所有异步完成时触发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| var p1 = new Promise(function(resolve){ setTimeout(function(){ console.log("p1"); resolve(); },1000) })
var p2 = new Promise(function(resolve){ setTimeout(function(){ console.log("p2"); resolve(); },2000) })
var p3 = new Promise(function(resolve){ setTimeout(function(){ console.log("p3"); resolve(); },3000) })
Promise.all([p1,p2,p3]).then(function(){ console.log("全部执行完毕") });
|
使用 .race()
来竞争,当有异步完成时触发。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| var p1 = new Promise(function(resolve){ setTimeout(function(){ console.log("p1"); resolve("p1"); },Math.random() * 1000) })
var p2 = new Promise(function(resolve){ setTimeout(function(){ console.log("p2"); resolve("p2"); },Math.random() * 1000) })
var p3 = new Promise(function(resolve){ setTimeout(function(){ console.log("p3"); resolve("p3"); },Math.random() * 1000) })
Promise.race([p1,p2,p3]).then(function(winner){ console.log(winner + "优先完成"); })
|
最后
Promise 也是一个 Monad (逃