写在前面
本文内容及代码均摘取出自廖雪峰老师的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)
})