浏览器支撑
http://caniuse.com/promises/embed/agents=desktop
What is Promise?
Promise是笼统异步处置惩罚对象以及对其举行种种操纵的组件。
说到 javascript 异步操纵,能够想到的是如许:
// 以 jQuery 的 ajax 为例
$.get('/get_url', function(result, status) {
if(status == 'success') {
alert('success');
}
if(status == 'error') {
alert('error');
}
});
关于 ajax 的 get 操纵来讲,是一个异步的历程,经由过程回调函数,在获得返回的时刻才会去实行操纵。
然则试想一下当操纵越来越多,回调内里还要回调的时刻,一层层回调函数是否是让人抓狂,不管在代码可读性照样编写效力来看都是很贫苦的。
看一下我们用 Promise 能够怎样做一个异步的操纵:
// 这个 getData 是我们预先实例好的一个 Promise 对象,怎样处置惩罚这个对象我们这里不议论
var promise = getData('/get_url');![图片形貌][3]
promise.then(function(result) {
console.log(result);
}).catch(function(error) {
console.log(error);
});
如许的作风是否是会更好呢,实行一个 promise,然后 then 内里传入回调函数,假如情愿,我们能够在 then 背面再更许多个 then,catch 能够捕获毛病,看起来代码清楚简明多了。
所以,promise的功用是能够将庞杂的异步处置惩罚轻松地举行模式化。
组织函数 Constructor
new Promise(executor);
new Promise(function(resolve, reject) { ... });
这里的 executor
是我们实例化一个 promise 对象时应当传入的参数,这个参数只一个函数,这个函数吸收两个参数 resolve
和reject
。
两个要领:
resolve(result)
在 promise 中实行这个要领示意胜利,会在实行以后实行背面的 then 所传入的函数,它吸收到的参数也会被 then 内里的函数吸收到,平常来讲参数为实行效果胜利时刻的数据;reject(error)
在 promise 中实行这个要领示意失利,他平常吸收一个 error 毛病参数,会被背面的 catch 捕获到毛病实行。
demo:
var testFoo = function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('success');
}, 2000);
});
};
testFoo().then(function(result) {
console.log(result);
}).catch(function(error) {
console.log(error);
});
在这里我们定义了一个 testFoo
函数,这个函数返回一个Promise
的实例化对象,两秒以后会实行resolve('success');
,示意胜利,传入一个参数,在两秒以后,我们then内里传入的函数实行了,吸收到了方才谁人参数;然则catch内里的函数并没有实行,由于我们没有在 promise 内里实行谢绝操纵。
假如我们在四秒以后实行 reject
操纵呢:
var testFoo = function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('success');
}, 2000);
setTimeout(function() {
reject('error');
}, 4000);
});
};
testFoo().then(function(result) {
console.log(result);
}).catch(function(error) {
console.log(error);
});
貌似只涌现resolve
的效果,由于一个 promise 没办法做屡次效果操纵。
我们就如许:
var testFoo = function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject('error');
}, 4000);
});
};
testFoo().then(function(result) {
console.log(result);
}).catch(function(error) {
console.log(error);
});
如今效果如我们所预感了。
PromiseStatus 状况
状况分为三种:
fulfilled
– Fulfilled 已完成,在resolve
时,挪用 then 的onFulfilled
函数;Rejected
– Rejected 谢绝,在reject
时,挪用 then 的onRejected
函数,或许 catch 内里的函数;unresolved
– Pending 守候,是 promise 初始化的时刻的状况。
promise 的 初始化状况为 unresolved,依据异步效果变成 fulfilled 或许 Rejected,一旦变成个中一个就不可转变,这也是我们之前上面为何实行了 resolve 以后再实行 reject 而没有效果的缘由了。
要领概述
快速要领
Promise.resolve()
这个是promise的静态要领
Promise.resolve(10).then(function(value){
console.log(value);
});
这个要领会让 Promise 马上进入 fulfilled 状况,平常用来测试用。
Promise.reject()
相应着我们有这个要领
Promise.reject('err').catch(function(err){
console.log(err);
});
实例要领
then(onFulfilled, onRejected)
这个要领详细是如许的,传入两个函数,一个处置惩罚fulfilled状况,另一个处置惩罚Rejected状况,平常运用我们只传入第一个函数,第二个放在 catch 来处置惩罚。catch(onRejected)
处置惩罚Rejected状况,能够这么明白catch(onRejected)
=promise.then(undefined, onRejected)
。
链式挪用
看看这个 demo:
var testFoo = function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(1);
}, 2000);
});
};
testFoo().then(function(result) {
console.log(result);
return ++result;
}).then(function(result) {
console.log(result);
return ++result;
}).then(function(result) {
console.log(result);
return ++result;
}).catch(function(error) {
console.log(error);
});
// 1
// 2
// 3
能够瞥见效果,这个要领的流程是什么样的呢?
第一个 then 函数和之前讲的一样,处置惩罚 promise 的 fulfilled,第二个 then 的函数是处置惩罚前一个 then 函数处置惩罚完的效果,他们之间参数通报的门路是前一个 then 函数 return 一个数据,然后后一个 then 函数吸收到这个参数。
假如你情愿,能够再背面加许多许多个 then,他们的流程主如果如许。
假如我们把 catch 提早呢?
var testFoo = function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(1);
}, 2000);
});
};
testFoo().then(function(result) {
console.log(result);
return ++result;
}).then(function(result) {
console.log(result);
return ++result;
}).catch(function(error) {
console.log(error);
}).then(function(result) {
console.log(result);
return ++result;
});
// 1
// 2
// 3
能够看出,效果一样,申明catch只会在发作 reject 的时刻挪用。
那假如在中心的一个 then 中抛出一个非常呢?
var testFoo = function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(1);
}, 2000);
});
};
testFoo().then(function(result) {
console.log(result);
return ++result;
}).then(function(result) {
console.log(result);
throw new Error("throw Error")
return ++result;
}).then(function(result) {
console.log(result);
return ++result;
}).catch(function(error) {
console.log(error);
});
// 1
// 2
// Error: throw Error
我们在第二个then中抛出一个非常,然后马上被 catch 捕获到,第三个 then 并没有实行。
到这里我们想一下从then的传参和捕获非常来看,新加一个 then 只是注册了一个回调函数那末简朴吗?
不不不,每次挪用then都邑返回一个新创建的promise对象,这就诠释了上面的统统缘由。
并发挪用
试想一个场景,我们实行多个异步操纵(ajax等等),然则我们想在这几个操纵都完成的时刻才去实行一个函数。
假如根据传统的要领来做,代码会很乱很散,症结不文雅。让我们尝试用 promise 。
先看这个 demo
var testFoo = function(time, value) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(value);
}, time * 1000);
});
};
var tasks = {
task1: function() {
return testFoo(1, 2);
},
task2: function() {
return testFoo(1.3, 3);
},
task3: function() {
return testFoo(1.5, 1);
}
};
var main = function() {
function recordValue(results, value) {
results.push(value);
console.log(value);
console.log(results);
return results;
}
var pushValue = recordValue.bind(null, []);
return tasks.task1().then(pushValue).then(tasks.task2).then(pushValue).then(tasks.task3).then(pushValue);
};
main().then(function(value) {
console.log(value);
});
// [2, 3, 1]
这么完成显著看起来缭乱,迥殊关于 main 函数,可读性也比较差。
那末有无更文雅的要领呢,答案:有!?。
Promise.all
Promise.all
要领吸收一个以 promise 对象为元素的数组,在悉数实行操纵完成后才回挪用then内里的要领,看代码:
var testFoo = function(time, value) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(value);
}, time * 1000);
});
};
var tasks = {
task1: function() {
return testFoo(1, 2);
},
task2: function() {
return testFoo(1.3, 3);
},
task3: function() {
return testFoo(1.5, 1);
}
};
var main = function() {
return Promise.all([tasks.task1(), tasks.task2(), tasks.task3()]);
}
main().then(function(result) {
console.log(result);
});
// [2, 3, 1]
我们吧要实行的 promise 对象作为数组的元素传给 Promise.all()
,Promise.all().then()
内里定义的函数吸收到一个数组,元素是这几个操纵返回的值,递次和 promise 对象放入的递次一样,比方第一个 promise 对象返回的值是2,那末效果的第一个元素就是2。
而且每个promise是同时实行的--并发。
在一切 promise 的状况为 FulFilled 的时刻才会去实行 then 内里的函数。
那末捕获非常呢?
修正一下例子:
var testFoo = function(time, value, err) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
if(err) {
reject(err);
return false;
}
resolve(value);
}, time * 1000);
});
};
var tasks = {
task1: function() {
return testFoo(1, 2, 'error');
},
task2: function() {
return testFoo(1.3, 3, 'error1');
},
task3: function() {
return testFoo(1.5, 1);
}
};
var main = function() {
return Promise.all([tasks.task1(), tasks.task2(), tasks.task3()]);
}
main().then(function(result) {
console.log(result);
}).catch(function(err) {
console.log(err);
});
// [2, 3, 1]
我们让个中2 promise 个抛出非常,看到捕获到了谁人非常,而且是捕获到第一个非常就住手了。
申明 all 的操纵是当一切 promise 状况为 FulFilled 的时刻才会实行 then 的操纵。而一旦有一个 Rejected 就catch这个非常,而且住手。
Promise.race
他和 Promise.all 一样,吸收一个 promise 对象构成的数组,也是并发实行,然则 Promise.race 是只需有一个promise对象进入 FulFilled 或许 Rejected 状况的话,就会继续举行背面的处置惩罚。
var testFoo = function(time, value) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(value);
}, time * 1000);
});
};
var tasks = {
task1: function() {
return testFoo(1, 2);
},
task2: function() {
return testFoo(1.3, 3);
},
task3: function() {
return testFoo(1.5, 1);
}
};
var main = function() {
return Promise.race([tasks.task1(), tasks.task2(), tasks.task3()]);
}
main().then(function(result) {
console.log(result);
});
// 2
能够看到,task1 最早完成,然后就拿到他的值举行 then 操纵。
原文来自我的博客 http://qiutc.me/post/promise-learn-note.html
迎接人人关注~