Promise.prototype.then() - JavaScript Promise 对象
Promise.prototype.then()
then()
方法返回一个Promise
。它最多需要有两个参数:Promise 的成功和失败情况的回调函数。
注意:如果忽略针对某个状态的回调函数参数,或者提供非函数(nonfunction)参数,那么then
方法将会丢失关于该状态的回调函数信息,但是并不会产生错误。如果调用then
的Promise
的状态(fulfillment 或 rejection)发生改变,但是then
中并没有关于这种状态的回调函数,那么then
将创建一个没有经过回调函数处理的新Promise
对象,这个新Promise
只是简单地接受调用这个then
的原Promise
的终态作为它的终态。
语法
p.then(onFulfilled[, onRejected]); p.then(value => { // fulfillment }, reason => { // rejection });
参数
onFulfilled
可选当 Promise 变成接受状态(fulfilled)时调用的函数
。该函数有一个参数,即接受的最终结果(the fulfillment value)。如果该参数不是函数,则会在内部被替换为(x)=> x
,即原样返回 promise 最终结果的函数onRejected
可选当 Promise 变成接受状态或拒绝状态(rejected)时调用的函数
。该函数有一个参数,即拒绝的原因(rejection reason
)。如果该参数不是函数,则会在内部被替换为一个"Thrower"函数(it throws an error it received as argument)。返回值
当一个Promise
完成(fulfilled)或者失败(rejected)时,返回函数将被异步调用(由当前的线程循环来调度完成)。具体的返回值依据以下规则返回。如果then
中的回调函数:
- 返回了一个值,那么
then
返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。 - 没有返回任何值,那么
then
返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为undefined
。 - 抛出一个错误,那么
then
返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。 - 返回一个已经是接受状态的 Promise,那么
then
返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。 - 返回一个已经是拒绝状态的 Promise,那么
then
返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。 - 返回一个未定状态(
pending
)的 Promise,那么then
返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。
下面是一个演示 then
方法的同步性的例子。
// using a resolved promise, the 'then' block will be triggered instantly, // but its handlers will be triggered asynchronously as demonstrated by the console.logs const resolvedProm = Promise.resolve(33); let thenProm = resolvedProm.then(value => { console.log("this gets called after the end of the main stack. the value received and returned is: " + value); return value; }); // instantly logging the value of thenProm console.log(thenProm); // using setTimeout we can postpone the execution of a function to the moment the stack is empty setTimeout(() => { console.log(thenProm); }); // 上面的代码会依次返回: // Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined} // "this gets called after the end of the main stack. the value received and returned is: 33" // Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 33}
描述
由于then
和Promise.prototype.catch()
方法都会返回 promise,它们可以被链式调用——这同时也是一种被称为复合(composition)的操作。
示例
使用then
方法
var p1 = new Promise((resolve, reject) => { resolve('成功!'); // or // reject(new Error("出错了!")); }); p1.then(value => { console.log(value); // 成功! }, reason => { console.error(reason); // 出错了! });
链式调用
then
方法返回一个Promise
对象,其允许方法链。
你可以传递一个匿名函数给then
,并且,如果它返回一个Promise
,一个等价的Promise
将暴露给后续的方法链。下面的代码片段使用setTimout
函数来模拟异步代码操作。
Promise.resolve("foo") // 1. 接收 "foo" 并与 "bar" 拼接,并将其结果做为下一个 resolve 返回。 .then(function(string) { return new Promise(function(resolve, reject) { setTimeout(function() { string += 'bar'; resolve(string); }, 1); }); }) // 2. 接收 "foobar", 放入一个异步函数中处理该字符串 // 并将其打印到控制台中, 但是不将处理后的字符串返回到下一个。 .then(function(string) { setTimeout(function() { string += 'baz'; console.log(string); }, 1) return string; }) // 3. 打印本节中代码将如何运行的帮助消息, // 字符串实际上是由上一个回调函数之前的那块异步代码处理的。 .then(function(string) { console.log("Last Then: oops... didn't bother to instantiate and return " + "a promise in the prior then so the sequence may be a bit " + "surprising"); // 注意 `string` 这时不会存在 'baz'。 // 因为这是发生在我们通过setTimeout模拟的异步函数中。 console.log(string); }); // logs, in order: // Last Then: oops... didn't bother to instantiate and return a promise in the prior then so the sequence may be a bit surprising // foobar // foobarbaz
当一个值只是从一个then
内部返回时,它将等价地返回Promise.resolve()
。
var p2 = new Promise(function(resolve, reject) { resolve(1); }); p2.then(function(value) { console.log(value); // 1 return value + 1; }).then(function(value) { console.log(value + ' - A synchronous value works'); }); p2.then(function(value) { console.log(value); // 1 });
如果函数抛出错误或返回一个拒绝的Promise,则then
将返回一个拒绝的Promise。
Promise.resolve() .then(() => { // 使 .then() 返回一个 rejected promise throw new Error('Oh no!'); }) .then(() => { console.log('Not called.'); }, error => { console.error('onRejected function called: ' + error.message); });
在其他情况下,一个 resolving Promise 会被返回。在下面的例子里,第一个then()
会返回一个用 resolving Promise 包装的42
,即使之前的 Promise 是 rejected 的。
Promise.reject() .then(() => 99, () => 42) // onRejected returns 42 which is wrapped in a resolving Promise .then(solution => console.log('Resolved with ' + solution)); // Resolved with 42
实际上,捕获 rejected promise 的需求经常大于使用then
的两种情况语法,比如下面这样的:
Promise.resolve() .then(() => { // 使 .then() 返回一个 rejected promise throw new Error('Oh no!'); }) .catch(error => { console.error('onRejected function called: ' + error.message); }) .then(() => { console.log("I am always called even if the prior then's promise rejects"); });
你也可以在另一个顶层函数上使用链式去实现基于 Promise API 的函数。
function fetch_current_data() { // fetch() API 返回了一个 Promise. // 这个函数提供了类似的API, // 这个函数除了实现 Promise,它还能够完成更多的工作。 return fetch('current-data.json').then(response => { if (response.headers.get('content-type') != 'application/json') { throw new TypeError(); } var j = response.json(); // maybe do something with j return j; // fulfillment value given to user of // fetch_current_data().then() }); }
如果onFulfilled
返回了一个 promise,then
的返回值就会被 Promise resolved 或者 rejected。
function resolveLater(resolve, reject) { setTimeout(function() { resolve(10); }, 1000); } function rejectLater(resolve, reject) { setTimeout(function() { reject(new Error('Error')); }, 1000); } var p1 = Promise.resolve('foo'); var p2 = p1.then(function() { // Return promise here, that will be resolved to 10 after 1 second return new Promise(resolveLater); }); p2.then(function(v) { console.log('resolved', v); // "resolved", 10 }, function(e) { // not called console.error('rejected', e); }); var p3 = p1.then(function() { // Return promise here, that will be rejected with 'Error' after 1 second return new Promise(rejectLater); }); p3.then(function(v) { // not called console.log('resolved', v); }, function(e) { console.error('rejected', e); // "rejected", 'Error' });
基于 promise 的window.setImmediate
polyfill
Using a Reflect.apply()
)method to create a(non-cancellable)setImmediate-style function.
const nextTick = (() => { const noop = () => {}; // literally const nextTickPromise = () => Promise.resolve().then(noop); const rfab = Reflect.apply.bind; // (thisArg, fn, thisArg, [...args]) const nextTick = (fn, ...args) => ( fn !== undefined ? Promise.resolve(args).then(rfab(null, fn, null)) : nextTickPromise(), undefined ); nextTick.ntp = nextTickPromise; return nextTick; })();
鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com
图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!