写在前面
本文内容及代码均摘取出自廖雪峰老师的 JavaScript 教程。
本文仅作为个人笔记,练习代码使用(所有的代码都需要自己手动敲上几遍),内容上也精简了很多。
相关知识还请阅读原文:Promise – JavaScript 教程
Promise
promise 是异步编程的一种解决方案,相比于传统解决方案 callback 更加的优雅。promise 避免了“回调地狱”的产生。
待实现的需求:
函数执行,1s 后输出 pending,2s 后输出 finished
- callback 方式:
(function print() {setTimeout(function(){console.log('pending');
setTimeout(function(){console.log('finished');
},1000)
},1000)
})()
- promise 方式:
function createPromise() {return new Promise(function(resolve,reject){setTimeout(resolve,1000)
});
}
createPromise().then(function(){console.log('pending');
return createPromise();}).then(function(){console.log('finished');
})
- ps:使用 promise 易犯的一个错误
let waitSecond = new Promise(function (resolve,reject){setTimeout(resolve,1000)
});
waitSecond.then(function(){console.log('pending');
return waitSecond;
}).then(function(){console.log('finished');
})
// 1 秒后,控制台同时输出 'pending' 和 'finished'
// 这是因为同一个 promise 只能改变一次状态
这样来看,似乎 promise 的实现更复杂一些。但若场景再复杂化:请求 test1,把请求结果作为参数去请求 test2,以此类推
function request(url, param, successFun, errorFun) {
$.ajax({
type: 'GET',
url: url,
param: param,
async: true, // 默认为 true, 即异步请求;false 为同步请求
success: successFun,
error: errorFun
});
}
- callback 方式(分步 ajax 请求)
request('test1.html', '', function(data1) {console.log('第一次请求成功, 这是返回的数据:', data1);
request('test2.html', data1, function (data2) {console.log('第二次请求成功, 这是返回的数据:', data2);
request('test3.html', data2, function (data3) {console.log('第三次请求成功, 这是返回的数据:', data3);
//request... 继续请求
}, function(error3) {console.log('第三次请求失败, 这是失败信息:', error3);
});
}, function(error2) {console.log('第二次请求失败, 这是失败信息:', error2);
});
}, function(error1) {console.log('第一次请求失败, 这是失败信息:', error1);
});
- promise 方式(分步 ajax 请求)
function sendRequest(url, param) {return new Promise(function(resolve, reject) {request(url, param, resolve, reject);
});
}
sendRequest('test1.html', '').then(function(data1) {console.log('第一次请求成功, 这是返回的数据:', data1);
return sendRequest('test2.html', data1);
}).then(function(data2) {console.log('第二次请求成功, 这是返回的数据:', data2);
return sendRequest('test3.html', data2);
}).then(function(data3) {console.log('第三次请求成功, 这是返回的数据:', data3);
}).catch(function(error) {
// 用 catch 捕捉前面的错误
console.log('sorry, 请求失败了, 这是失败信息:', error);
});
promise 练习(结合 setTimeout、DOM 操作等)
- 生成一个 0 - 2 之间的随机数,如果大于 1,则等待相应时间后返回成功,否则返回失败:
// 清除最近一次 log:var logging = document.getElementById('log-text');
while(logging.children.length > 0) {logging.removeChild(logging.children[logging.children.length - 1]);
}
// 输出结果到页面:function log(text) {var p = document.createElement('p');
p.innerText = text;
logging.appendChild(p);
}
// 构建 promise 并执行
new Promise((resolve,reject) => {var timeOut = Math.random() * 2;
log('timeOut:' + timeOut);
if (timeOut > 1) {
// 使用常规传参
setTimeout(resolve,timeOut * 1000,'200 OK');
} else {
// 使用匿名函数
setTimeout(() => {// log('do something');
reject('setTimeout is:' + timeOut)
},timeOut * 1000);
// 可见:使用匿名函数更灵活,比如在 resolve、reject 前调其他方法
}
}).then((result) => {log('成功:' + result);
}).catch((reason) => {log('失败:' + reason);
})
- 串行执行一系列需要异步计算获得结果的任务,比如执行先平方,再求和,再平方:
// 清除最近一次 log:var logging = document.getElementById('log-text');
while(logging.children.length > 0) {logging.removeChild(logging.children[logging.children.length - 1]);
}
// 输出结果到页面:function log(text) {var p = document.createElement('p');
p.innerText = text;
logging.appendChild(p);
}
// 返回 promise 的乘法运算
function multiply(input) {return new Promise((resolve,reject) => {log('Call multiply():');
log('Calculate' + input + 'x' + input);
setTimeout(resolve,1000,input * input);
})
}
// 返回 promise 的加法运算
function sum(input) {return new Promise((resolve,reject) => {log('Call sum():');
log('Calculate' + input + '+' + input);
setTimeout(resolve,1000,input + input);
})
}
new Promise((resolve,reject) => {log('start new Promise...');
resolve(123);
}).then(multiply)
.then(sum)
.then(multiply)
.then(sum)
.then((result) => {log('The result is:' + result)
})