1
const promise = new Promise((resolve, reject) => {
console.log(1);
console.log(2);
});
promise.then(() => {
console.log(3);
});
console.log(4);
// 1、2、4
Promise 的执行器函数是同步执行的,1、2会在4前面;没有resolve、 reject,Promise 状态一直是pending,.then不执行。
2
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
resolve('resolve1')
})
const promise2 = promise1.then(res => {
console.log(res)
})
console.log('1', promise1);
console.log('2', promise2);
// 结果
promise1
1 Promise{<resolved>: resolve1}
2 Promise{<pending>}
resolve1
需要注意的是,直接打印promise1,会打印出它的状态值和参数。
1、script是一个宏任务,按照顺序执行这些代码;
2、首先进入Promise,执行该构造函数中的代码,打印promise1;
3、碰到resolve函数, 将promise1的状态改变为resolved, 并将结果保存下来;
4、碰到promise1.then这个微任务,将它放入微任务队列;
5、promise2是一个新的状态为pending的Promise;
6、执行同步代码1, 同时打印出promise1的状态是resolved;
7、执行同步代码2,同时打印出promise2的状态是pending;
8、宏任务执行完毕,查找微任务队列,发现promise1.then这个微任务且状态为resolved,执行它
console.log(‘1’, promise1)这里,promise1不一定输出Promise{<resolved>: resolve1}
,因为在某些旧版工具或特定环境下不会立即计算 Promise 的最终状态。
3
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
// 结果
1
Promise {<fulfilled>: undefined}
Promise.resolve()的第一个参数。使用这个静态方法,实际上可以把任何值都转换为一个期约:
console.log(Promise.resolve(3))
//
Promise { 3 }
Promise.prototype.then()是为期约实例添加处理程序的主要方法。这个 then()方法接收最多两个参数:onResolved 处理程序和 onRejected 处理程序。传给 then()的任何非函数类型的参数都会被静默忽略。如果想只提供 onRejected 参数,那就要在 onResolved 参数的位置上传入 undefined。这样有助于避免在内存中创建多余的对象,对期待函数参数的类型系统也是一个交代。
// 不传 onResolved 处理程序的规范写法
p2.then(null, () => onRejected('p2'));
若调用 then()时不传处理程序,则原样向后传:
let p1 = Promise.resolve('foo');
// 若调用 then()时不传处理程序,则原样向后传
let p2 = p1.then();
setTimeout(console.log, 0, p2); // Promise <resolved>: foo
4
let p1 = Promise.resolve('foo');
let p10 = p1.then(() => { throw 'baz'; });
// Uncaught (in promise) baz
setTimeout(console.log, 0, p10); // Promise <rejected> baz
抛出异常会返回拒绝的期约throw 'baz';
5
const promise = Promise.resolve().then(() => {
return promise;
})
promise.catch(console.err)
//
Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
.then 或 .catch 返回的值不能是 promise 本身,否则会造成死循环。
6
Promise.resolve('1')
.then(res => {
console.log(res)
})
.finally(() => {
console.log('finally')
})
Promise.resolve('2')
.finally(() => {
console.log('finally2')
return '我是finally2返回的值'
})
.then(res => {
console.log('finally2后面的then函数', res)
})
//
1
finally2
finally
finally2后面的then函数 2
7
function runAsync (x) {
const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))
return p
}
function runReject (x) {
const p = new Promise((res, rej) => setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x))
return p
}
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)])
.then(res => console.log(res))
.catch(err => console.log(err))
//结果
// 1s后输出
1
3
// 2s后输出
2
Error: 2
// 4s后输出
4
Promise.all如果所有期约都成功解决,则合成期约的解决值就是所有包含期约解决值的数组,按照迭代器顺序;
如果有期约拒绝,则第一个拒绝的期约会将自己的理由作为合成期约的拒绝理由。之后再拒绝的期约不会影响最终期约的拒绝理由。不过,这并不影响所有包含期约正常的拒绝操作。合成的期约会静默处理所有包含期约的拒绝操作
8
function runAsync (x) {
const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))
return p
}
Promise.race([runAsync(1), runAsync(2), runAsync(3)])
.then(res => console.log('result: ', res))
.catch(err => console.log(err))
//
1
'result: ' 1
2
3
Promise.race无论是解决还是拒绝,只要是第一个落定的期约,Promise.race()就会包装其解决值或拒绝理由并返回新期约。其他的期约正常执行。
9
async function async1 () {
console.log('async1 start');
await new Promise(resolve => {
console.log('promise1')
})
console.log('async1 success');
return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')
//
script start
async1 start
promise1
script end
这里需要注意的是在async1中await后面的Promise是没有返回值的,也就是它的状态始终是pending状态,所以在await之后的内容是不会执行的,包括async1后面的 .then。
10
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
console.log("script start");
setTimeout(function() {
console.log("setTimeout");
}, 0);
async1();
new Promise(resolve => {
console.log("promise1");
resolve();
}).then(function() {
console.log("promise2");
});
console.log('script end')
//
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
事件循环的工作方式大致如下:
1、执行栈(Stack)是空的,浏览器从宏任务队列(Macrotask Queue)中取出一个宏任务执行。
2、执行宏任务的过程中,如果遇到微任务(例如通过Promise.then、process.nextTick(Node.js)、MutationObserver(浏览器)等产生的),则将这些微任务添加到微任务队列(Microtask Queue)中。
3、当前宏任务执行完毕后,会查看微任务队列是否有微任务。如果有,则立即执行所有的微任务,直到微任务队列清空。
4、微任务队列清空后,事件循环会再次从宏任务队列中取出一个宏任务执行,重复上述步骤。
11
async function async1 () {
await async2();
console.log('async1');
return 'async1 success'
}
async function async2 () {
return new Promise((resolve, reject) => {
console.log('async2')
reject('error')
})
}
async1().then(res => console.log(res))
//
async2
Uncaught (in promise) error
如果async函数中抛出了错误,就会终止错误结果,不会继续向下执行。
12
期约已经变为resolved状态,所以后面的resolve()不会再执行
13
const p1 = new Promise((resolve) => {
setTimeout(() => {
resolve('resolve3');
console.log('timer1')
}, 0)
resolve('resovle1');
resolve('resolve2');
}).then(res => {
console.log(res) // resolve1
setTimeout(() => {
console.log(p1)
}, 1000)
}).finally(res => {
console.log('finally', res)
})
//
resolve1
finally undefined
timer1
Promise{<resolved>: undefined}
Promise.prototype.then()是为期约实例添加处理程序的主要方法。这个 then()方法接收最多两个参数:onResolved 处理程序和 onRejected 处理程序。传给 then()的任何非函数类型的参数都会被静默忽略。
处理程序的返回值会通过Promise.resolve()包装来生成新期约。如果没有提供这个处理程序,则 Promise.resolve()就会包装上一个期约解决之后的值。如果没有显式的返回语句,则 Promise.resolve()会包装默认的返回值 undefined。如下:
let p1 = Promise.resolve('foo');
// 若调用 then()时不传处理程序,则原样向后传
let p2 = p1.then();
setTimeout(console.log, 0, p2); // Promise <resolved>: foo
// 没有显示的返回值,隐式地返回 undefined
let p3 = p1.then(() => undefined);
let p4 = p1.then(() => {});
let p5 = p1.then(() => Promise.resolve());
setTimeout(console.log, 0, p3); // Promise <resolved>: undefined
setTimeout(console.log, 0, p4); // Promise <resolved>: undefined
setTimeout(console.log, 0, p5); // Promise <resolved>: undefined
// 有显示返回值
let p6 = p1.then(() => 'bar');
let p7 = p1.then(() => Promise.resolve('bar'));
setTimeout(console.log, 0, p6); // Promise <resolved>: bar
setTimeout(console.log, 0, p7); // Promise <resolved>: bar
14
Promise.resolve().then(() => {
console.log('1');
throw 'Error';
}).then(() => {
console.log('2');
}).catch(() => {
console.log('3');
throw 'Error';
}).then(() => {
console.log('4');
}).catch(() => {
console.log('5');
}).then(() => {
console.log('6');
});
//
1
3
5
6
抛出异常会返回拒绝的期约,返回错误值不会触发拒绝行为。.catch()方法用于给期约添加拒绝处理程序。这个方法只接收一个参数:
onRejected 处理程序。事实上,这个方法就是一个语法糖,调用它就相当于调用 Promise.prototype. then(null, onRejected)。