参考链接:
Promise.then链式调用顺序(这一篇详细讲解then中嵌套promise和各种情况说明,必看,研究)
《ES6标准入门》(阮一峰)--16.Promise 对象(这一篇讲解promise比较全,有promise的各种方法讲解)
Promise基本使用及方法介绍(promise讲解比较全,辅助参考)
Promise中then的执行顺序详解(有简化版then实现,参考)
面试官:“你能手写一个 Promise 吗”(手写then,研究,未看)
题目七:并发加载三个图片
Promise的含义:
Promise 是一个对象,从它可以获取异步操作的消息。Promise 是目前前端解决异步问题的统一方案
Promise对象有以下两个特点:
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从进行中变为已成功和从进行中变为已失败。
只要这两种情况发生,状态就不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。
promise优点:
promise对象,可以将 异步操作 以 同步操作的流程 表达出来,避免层层嵌套
Promise缺点:
首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。
其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
第三,当处于进行中状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
promise的基本用法:
promise内部是同步的,但是then方法是异步的
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
resolve 函数的作用是,将Promise 对象的状态从“未完成”变为“成功”(即从 pending 变为 fulfilled),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject 函数的作用是,将Promise 对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise实例生成以后,可以用then方法分别指定fulfilled状态和rejected状态的回调函数。
Promise.then(function(value) {
// success
}, function(error) {
// failure
})
then方法可以接受两个回调函数作为参数。第一个回调函数是Promise 对象的状态变为resolved时调用,第二个回调函数是Promise 对象的状态变为rejected时调用。
其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise 对象传出的值作为参数。
下面是一个用Promise对象实现的 Ajax 操作的例子。
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});
resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例
const p1 = new Promise(function (resolve, reject) {
// ...
});
const p2 = new Promise(function (resolve, reject) {
// ...
resolve(p1);
})
上面代码中,p1和p2都是 Promise 的实例,但是p2的resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作。
注意,这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;
如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。
Promise.prototype.then():
总结三点:
(1) 当前一个then中的代码都是同步执行的,执行结束后第二个then即可注册进入微任务队列。
(2) 当前一个then中有return 关键字,需要return的内容完全执行结束,第二个then才会注册进入微任务队列。
(3)then 方法接受的参数是函数,而如果传递的并非是一个函数,它实际上会将其解释为 then(null),这就会导致前一个 Promise 的结果会穿透下面。
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
// 1
Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。
前面说过,then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
const getJSON = ()=>(new Promise((resolve,reject)=>resolve(1)))
getJSON().then(function(json) {
console.log(json)
return json;
}).then(function(post) {
console.log(post)
});
上面的代码使用then方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。
采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),
这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。
const getJSON = (num)=>(new Promise((resolve,reject)=>resolve(num)))
getJSON(1).then(function(post) {
return getJSON(2);
}).then(function (comments) {
console.log("resolved: ", comments);
}, function (err){
console.log("rejected: ", err);
});
// 打印:resolved: 2
上面代码中,第一个then方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。
如果变为resolved,就调用第一个回调函数,如果状态变为rejected,就调用第二个回调函数。
Promise.resolve():
promise.resolve()可以将对象转换为promise对象
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
Promise.resolve方法的参数分成四种情况。
(1)参数是一个 Promise 实例
如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
(2)参数是一个thenable对象
thenable对象指的是具有then方法的对象,比如下面这个对象。
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
console.log(value); // 42
});
上面代码中,thenable对象的then方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42。
(3)参数不是具有then方法的对象,或根本就不是对象
如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。
const p = Promise.resolve('Hello');
p.then(function (s){
console.log(s)
});
// Hello
上面代码生成一个新的 Promise 对象的实例p。由于字符串Hello不属于异步操作(判断方法是字符串对象不具有 then 方法),返回 Promise 实例的状态从一生成就是resolved,所以回调函数会立即执行。Promise.resolve方法的参数,会同时传给回调函数。
Promise.prototype.catch():
Promise.prototype.catch() 是 .then(null, rejection) 的别名,用于指定发生错误时的回调函数
如果promise实例对象的状态变为rejected,
就会触发 catch() 方法指定的回调函数
如果 .then() 方法指定的回调函数在运行中抛出错误,也会被 catch() 方法捕获
promise对象的错误具有冒泡性质,
会一直向后传递,直到被捕获为止
( 也就是说错误总是会被下一个catch语句捕获 )
一般来说,不要在.then()方法中定义rejected状态的回调函数,
而总是使用 .catch()方法
一般总是建议,promise对象后要跟 catch()方法,这样可以处理 promise内部发生法的错误,catch() 方法返回的还是promise对象,
因此后面还可以接着调用 then() 方法
catch() 方法中还能再抛错误,如果 catch()方法抛出错误后,后面没有catch()方法,错误就不会被捕获,也不会传递到外层。
如果catch()方法抛出错误后,后面有then()方法,会照常执行,后面有catch()方法,错误还会被再一次捕获
async和await:
Async返回的是Promise对象
async/await其实就是promise和generator的语法糖:
async function demo01() {
console.log(1)
return ‘demo1’;
}
demo01().then(function(a){
console.log(a)
});
输出结果为1,demo1
async用来表示函数是异步的,定义的函数会返回一个promise对象,可以使用then方法添加回调函数。上列代码中的async函数中的console.log(1)可以当一个同步的队列执行,也就是说但你在定义async function的时候 里面的代码是以同步的方式执行,只不过async的返回是一个promise,可以用.then()的方式去执行回调,如同上述内容。若 async 定义的函数有返回值,return ‘demo1’;相当于Promise.resolve('demo1’),没有声明式的 return则相当于执行了Promise.resolve();
await是和async一起来使用,一般为:
async function demo2(){
console.log(7)
await a()
console.log(6)
}
demo2()
function a() {
console.log(‘demo2’)
}
当他和promise一起用的话:
async myFun( ){ await new Promise(resolve=>{ }) }
总结:
一般async与await同步出现
async返回promise对象
await出现在async函数内部,单独只用会报错
componentDidMount() {
const funSync1 = () => console.log('我是同步函数1111111')
const funSync2 = () => console.log('我是同步函数2222222')
const funAsync = async () => { // async关键字,定义的函数是异步函数,返回promise对象
await funSync1()
}
funAsync().then(funSync2())
console.log('bbbb')
}
// 先把两个同步函数变成了异步,在异步函数中,先执行funSync1,后执行funSync2
// 使用async关键字后,会把同步包装成的异步函数,按同步方式执行
// 所以最后得到的输出顺序是:
// 我是同步函数1111111
// 我是同步函数2222222
// bbbb
异步和同步:
同步直接拿到结果
异步不能直接拿到结果
回调不一定用在异步,也可以用在同步
异步不一定要用到回调,也可以用轮询。
异步任务不能拿到结果
异步任务完成时调用回调
结果作为参数
下面是一些例子,也有面试题,主要用来辅助弄懂js执行的顺序和promise.then执行顺序:
例子1:
const p1 = () => (new Promise((resolve, reject) => {
console.log(1);
let p2 = new Promise((resolve, reject) => {
console.log(2);
const timeOut1 = setTimeout(() => {
console.log(3);
resolve(4); // 不执行代码,因为p2的promise对象已经有结果
}, 0)
resolve(5);
});
resolve(6);
p2.then((arg) => {
console.log(arg);
});
}));
const timeOut2 = setTimeout(() => {
console.log(8);
const p3 = new Promise(reject => {
reject(9);
}).then(res => {
console.log(res)
})
}, 0)
p1().then((arg) => {
console.log(arg);
});
console.log(10);
// 打印结果:1,2,10,5,6,8,9,3
第一轮
宏任务:timeOut2,timeOut1
微任务:p2.then,p1.then(本轮结束前清空)
打印:1,2,10,5,6
第二轮
宏任务:timeOut2,timeOut1
微任务:p3.then(本轮结束前清空)
打印:8,9
第三轮
宏任务:timeOut1
微任务:
打印:3
例子2:
console.log('script start');
// Promise.resolve('foo') 等价于 new Promise(resolve => resolve('foo')),所以会先让同步任务先执行,所以这里打印script start,然后是script end。
setTimeout(function () {
console.log('setTimeout---0');
}, 0);
setTimeout(function () {
console.log('setTimeout---200');
setTimeout(function () {
console.log('inner-setTimeout---0');
});
Promise.resolve().then(function () {
console.log('promise5');
});
}, 200);
Promise.resolve().then(function () {
console.log('promise1');
// 每个new promise内有resolve会先优先于.then执行,所以这里会先打印promise1,然后打印promise3,再打印promise2(个人理解,源码类似这个逻辑)
}).then(function () {
console.log('promise2');
});
Promise.resolve().then(function () {
console.log('promise3');
});
console.log('script end');
// 执行结果: script start,script end,promise1,promise3,promise2,setTimeout---0,setTimeout---200,promise5,inner-setTimeout---0
例子3:
const promise = new Promise((resolve, reject) => {
console.log(1)
setTimeout(() => {
console.log('once')
resolve('success')
}, 1000)
})
// 1打印后,promise.then刚开始没有执行,因为promise对象还没有结果,也就是状态还是pendding,等到执行setTimeout后有了状态后才执行promise.then
// 另外因为状态改变后不会再改变,所以两个promise.then打印都是一样结果
promise.then((res) => {
console.log(res)
})
promise.then((res) => {
console.log(res)
})
// 执行结果:1,once,success,success
例子4:
let thenable = {
then: function(resolve, reject) {
resolve(6);
}
};
// let p = Promise.resolve();
let p = new Promise((resolve, reject) =>{
resolve(7)
});
setTimeout(()=>{
console.log(1)
},0)
// Promise.resolve()方法返回一个新的 Promise 对象,状态为resolved。Promise.resolve().then就是微任务,所有比setTimeout提前打印
// promise.resolve()方法:参数不是具有then方法的对象,或根本就不是对象(也就是2,5,4)和参数是一个promise对象(也就是7),他们的优先级高于参数是一个thenable对象
Promise.resolve().then(()=>{
console.log(2)
})
Promise.resolve(thenable).then((value)=>{
console.log(value)
})
Promise.resolve(p).then((v)=>{
console.log(v)
})
Promise.resolve('5').then(()=>{
console.log('5')
})
Promise.resolve().then(()=>{
console.log(4)
})
console.log(3)
//执行结果: 3,2,7,5,4,6,1
例子5:
const first = () => (new Promise((resolve, reject) => {
console.log(3)
let p = new Promise((resolve, reject) => {
console.log(7)
setTimeout(() => {
console.log(5)
resolve(6)
}, 0)
resolve(1)
})
resolve(2)
p.then((arg) => {
console.log(arg)
})
}))
console.log(4)
// 这道题没什么特殊,主要指出要注意new Promise有没有被放在函数里,如果放在函数里,是要等到被调用(first())才会执行,而不是new promise就直接执行了
first().then((arg) => {
console.log(arg)
})
// 执行结果: 4,3,7,1,2,5
// 第一轮
// 宏任务:setTimeout
// 微任务:p.then,first.then
// 打印:4,3,7,1,2
// 第二轮
// 宏任务:setTimeout
// 微任务:
// 打印:5
例子6:
setTimeout(() => {
console.log("0")
}, 0)
new Promise((resolve,reject)=>{ // promise1
console.log("1")
resolve() // 第一个resolve
}).then(()=>{
console.log("2")
new Promise((resolve,reject)=>{ // promise2
console.log("3")
resolve() // 第二个resolve
}).then(()=>{
console.log("4")
}).then(()=>{
console.log("5")
})
}).then(()=>{
console.log("6")
})
new Promise((resolve,reject)=>{ // promise3
console.log("7")
resolve() // 第三个resolve
}).then(()=>{
console.log("8")
})
// 首先执行两个new Promise打印1,7,然后是resolve1和resolve3进入队列。执行resolve1,打印2,3,resolve2进入队列(这个时候对于promise1的第一个then来说,已经有了fullfilled状态,所以promie1第二个then也进入队列),
// 所以打印8,4, 6,5,最后打印0
// 执行结果:1,7,2,3,8,4, 6,5,(这一步要注意,promise1.then是先进入任务队列,不是5,6),0
例子7:
async function async1() {
console.log('async1 start')
await async2() // 相当于async2().then(() => {}),所以下面这个'async1 end'是先被放到微任务队列
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(() => {
console.log('setTimeout')
}, 0)
async1()
new Promise(function (resolve) {
console.log('promise1')
resolve()
}).then(function () {
console.log('promise2')
})
console.log('script end')
// 这里比较容易弄错的是async2,async1 end的位置。async1 start之后为什么会马上执行async2,应该是这个await的作用(变异步为同步,必须等待await后的函数先执行)
// 然后就是await async2()相当于async2().then(() => {}),所以下面这个'async1 end'是先被放到微任务队列,Promise.then后面放入微任务队列,所以async1 end比promise2先执行。
// 答案依次:script start ==> async1 start ==> async2 ==> promise1 ==>
// script end ==> async1 end ==> promise2 ==> setTimeOut
例子8:
// async用来表示函数是异步的,定义的函数会返回一个promise对象,可以使用then方法添加回调函数。
// 也就是说你在定义async function的时候 里面的代码是以同步的方式执行,只不过async的返回是一个promise,可以用.then()的方式去执行回。
// 若 async 定义的函数有返回值,return ‘demo1’;相当于Promise.resolve('demo1’),没有声明式的 return则相当于执行了Promise.resolve();
async function demo01() {
console.log(1)
return 'demo1';
}
console.log('0')
demo01().then(function(a){
console.log(a)
});
console.log('8')
async function demo2(){
console.log(7)
await a()
console.log(6)
}
demo2()
let promise = new Promise(function(resolve, reject){
resolve(5)
console.log(3)
setTimeout(function(){console.log(4)})
})
console.log(2)
promise.then(function(a){
console.log(a)
})
function a(){
console.log('demo2')
}
// 0,1,8,7,demo2,3,2,demo1,6,5,4
例子9:有点难
const p1 = Promise.resolve();
let p3;
const p2 = new Promise(function(resolve, reject){
// 依赖p1的状态,比p1延迟了两个tick即ticke-3执行then
p3 = new Promise(res => res(p1));
// 等价于p1.then(tick1).then(tick2).then(logp3)
p3.then(() => {
// tick-3
console.log('p3')
resolve('ok');
})
});
p1.then(() => {
// tick-1
console.log('p1-1')
}).then(() => {
// tick-2
console.log('p1-2')
}).then(() => {
// tick-3
console.log('p1-3')
})
p2.then(function(data) {
// p2在tick-3时resolve则本函数在tick-4执行
console.log('p2-1')
}).then(function(data) {
// tick-5
console.log('p2-2')
}).then(function(data) {
// tick-6
console.log('p2-3')
})
p3.then(function(data) {
// 与p2内部的then在同一时刻即tick-3
console.log('p3-1')
}).then(function(data) {
// tick-4
console.log('p3-2')
}).then(function(data) {
// tick-5
console.log('p3-3')
})
根据不同的tick整理顺序可得:
// tick-1: p1-1
// tick-2: p1-2
// tick-3: p3,p3-1,p1-3 【由于p3先入栈tick3任务故在p1-3之前】
// tick-4: p2-1,p3-2
// tick-5: p2-2,p3-3
// tick-5: p2-3
如果把p3部分的代码转换下是等效于下面这段的
const p2 = new Promise(function(resolve, reject){
// 依赖p1的状态,比p1延迟了两个tick即ticke-3执行then
const noop = () => void 0;
p3 = p1.then(noop).then(noop);
// 等价于p1.then(tick1).then(tick2).then(logp3)
p3.then(() => {
// tick-3
console.log('p3')
resolve('ok');
})
});
例子10:
// 下面是两个例子
// 例子1:
const p1 = new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('fail')), 3000)
})
const p2 = new Promise(function (resolve, reject) {
setTimeout(() => {
console.log('p2')
resolve(p1)
}, 1000)
})
p2
.then(result => console.log(result))
.catch(error => console.log(error))
// 打印结果:p2,Error:fail
// 上面代码中,p1是一个 Promise,3 秒之后变为rejected。p2的状态在 1 秒之后改变,resolve方法返回的是p1。由于p2返回的是另一个 Promise,
// 导致p2自己的状态无效了,由p1的状态决定p2的状态。所以,后面的then语句都变成针对后者(p1)。又过了 2 秒,p1变为rejected,导致触发catch方法指定的回调函数。
// 注意,调用resolve或reject并不会终结 Promise 的参数函数的执行。
new Promise((resolve, reject) => { // 例子2:
resolve(1);
console.log(2);
}).then(r => {
console.log(r);
});
// 2
// 1
// 上面代码中,调用resolve(1)以后,后面的console.log(2)还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,
// 总是晚于本轮循环的同步任务。
// 一般来说,调用resolve或reject以后,Promise 的使命就完成了,后继操作应该放到then方法里面,而不应该直接写在resolve或reject的后面。
// 所以,最好在它们前面加上return语句,这样就不会有意外。
new Promise((resolve, reject) => {
return resolve(1);
// 后面的语句不会执行
console.log(2);
})
例子11:
const getJSON = (num)=>(new Promise((resolve,reject)=>resolve(num)))
getJSON(1).then(function(json) {
console.log(json)
return json+1;
}).then(function(post) {
console.log(post)
});
// 打印:1,2
const getJSON = (num)=>(new Promise((resolve,reject)=>resolve(num)))
getJSON(1).then(function(post) {
return getJSON(2);
}).then(function (comments) {
console.log("resolved: ", comments);
}, function (err){
console.log("rejected: ", err);
});
// 打印:resolved: 2
例子12:重要
promise.then内包含prmise.then,但是内部这个promise前面没有return的情况
new Promise((resolve, reject) => {
console.log("promise")
resolve()
})
.then(() => { // 执行.then的时候生成一个promise是给最后一个.then的
console.log("then1")
new Promise((resolve, reject) => {
console.log("then1promise")
resolve()
})
.then(() => {// 执行这个.then的时候,生成的promise是下面一个then的
console.log("then1then1")
setTimeout(()=>{
console.log('setTimeout')
},0)
})
.then(() => {
console.log("then1then2")
})
})
.then((res) => {
// 这个
console.log("then2",res)
})
// 执行结果:promise,then1,then1promise,then1then1,then2 undefined,then1then2,setTimeout
例子13:重要
promise.then内包含prmise.then,但是内部这个promise前面有return的情况
new Promise((resolve, reject) => {
console.log("promise")
resolve()
})
.then(() => { // 执行.then的时候生成一个promise是给最后一个.then的
console.log("then1")
return new Promise((resolve, reject) => {
console.log("then1promise")
resolve()
})
.then(() => {// 执行这个.then的时候,生成的promise是下面一个then的
console.log("then1then1")
setTimeout(()=>{
console.log('setTimeout')
},0)
})
.then(() => {
console.log("then1then2")
})
})
.then((res) => {
// 这个
console.log("then2",res)
})
// 注意:.then1函数体有了return返回值,是一个Promise对象,而且是then1then2执行完返回的匿名Promise对象。所以只有等这个Promise对象resolve了之后,才会执行then2回调函数体的逻辑,所以’then2’最后才会打印。
// 执行结果:promise,then1,then1promise,then1then1,then1then2,then2 undefined,setTimeout
关于例子12和例子13,说说自己的一点观点:内部promise在resolve后立即执行后面的then(其他不是包含promise也是这样),然后会跳出来执行外部promise的一个then,而不是继续执行内部promise的下一个then。如果有return,情况就不一样了。
例子14:难,不懂,待解释
1. 当Promise对象作为resolve的参数时
const p = Promise.resolve();
const p1 = Promise.resolve(p); //就是p
const p2 = new Promise(res => res(p)); //新建一个对象,对象状态依赖p
// res(p)可以看作 await p1; await resolve();
// 或者p.then(data => getData()).then(() => p2.resolve())
// 首先;p1 === p; p2!===p
// 那么,p1是一个fulfilled状态的对象;p2状态需要运行后求得
console.log(p === p1); // true
console.log(p === p2); // false
p1.then(() => {
console.log('p1-1');
}).then(() => {
console.log('p1-2');
}).then(() => {
console.log('p1-3');
})
p2.then(() => { //p-2.resolve之后才能调用回调函数
console.log('p2-1');
}).then(() => {
console.log('p2-2');
}).then(() => {
console.log('p2-3');
})
p.then(() => {
console.log('p-1');
}).then(() => {
console.log('p-2');
}).then(() => {
console.log('p-3');
})
// 运行结果
// getData()
// p1-1
// p-1
// 前面两个打印因为本身状态已经resolve了,所以直接出结果
// resolve()
// p1-2
// p-2
// p2-1
// p1-3
// p-3
// p2-2
// p2-3
// 后面打印p2-1是等到p运行resolve后才开始打印
例子15:难
2. 当Promise的resolve方法在另一个Promise对象的then方法中运行时,变异步;
例子12和例子13类似:p1要等resolve才能执行后面的then,所以p3先执行了。只要有resolve,就会先执行属于那个resolve的then,然后执行另外一个promise的resolve的then,最后才会继续第一个resolve接下去的then
let p3;
p1 = new Promise(resolve => {
p3 = new Promise(res => res());
p3.then(() => {
console.log('p3')
resolve(); // resolve()方法用在then方法中,变为异步执行
})
})
p1.then(() => {
console.log('p1-1');
}).then(() => {
console.log('p1-2');
})
p3.then(() => {
console.log('p3-1')
}).then(() => {
console.log('p3-2')
})
// 执行结果:p3,p3-1,p1-1,p3-2,p1-2
例子16:
new Promise((r,rj) => {
console.log('外p');
r();
}).then(() => {
console.log('外then1');
new Promise(((r,rj) => {
console.log('内p');
r();
})).then(() => {
console.log('内then1');
return new Promise((r, rj) => {r();});
}).then(() => {
console.log('内then2');
});
}).then(() => {
console.log('外then2');
}).then(() => {
console.log('外then3');
}).then(() => {
console.log('外then4');
});
// return new Promise((r, rj) => {r();}) 等同于
// return new Promise((r, rj) => {r();}).then(()=>{console.log(1)}).then(()=>{console.log(2)}).then(()=>{console.log(3)});
// 执行结果:外p,外then1,内p,内then1, 外then2,外then3,外then4,内then2,
例子17:------
// 例子1:
// await 不过是generator和promise结合后的一种语法糖
// await 会生成一个 Promise ,以其后表达式的值 resolve 这个 Promise(类似 Promise.resolve()),并在它的 then 回调里执行 await 返回之后的一切,同时结束程序的执行。
function doA1(){
new Promise( function (resolve) {
console.log(11);
resolve();
}).then(o=>{
console.log(12);
}).then(o=>{
console.log(13);
}).then(o=>{
console.log(14);
})
}
await doA1();
console.log(2);
//执行结果顺序为 11 12 2 13 14
// 按代码执行顺序,首先初始事件循环:
// 1.Promise 的 executor 参数是立即执行的,所以马上打印 11。
// 2.因为马上 resolve 了,后面跟着 then 故 promise 进入微事件队列中,继续执行其它平台代码。
// 3.await 因为跟了一个非 Promise 的值所以会自动包上一层 Promise.resolve,即无论如何都会至少等一个微事件周期。所以得到的 undefined 也进入微事件队列。
// await 阻塞了,本事件循环准备结束,开始清微事件队列
// 1.先是前面 11 得到的 promise,处理 then 回调打印 12,后面的 promise 继续入微事件队列。
// 2.接着是 await 得到 undefined,因为没有赋值,被丢弃。
// 3.await 得到了值,不再阻塞,继续往下执行打印 2。
// 4.await 后的平台代码执行完毕,微事件队列中还有 12 得到 promise。
// 5.重复上边过程打印 13 和 14
// 6.微事件队列已清空,本事件循环结束。
// 例子2:
// 返回了 Promise 那么 await 就会等这个 Promise 都 resolve 了才会继续往下执行。
function doA1(){
return new Promise( function (resolve) {
console.log(11);
resolve();
}).then(o=>{
console.log(12);
}).then(o=>{
console.log(13);
}).then(o=>{
console.log(14);
})
}
await doA1();
console.log(2);
//执行结果顺序为 11 12 13 14 2
例子18:难
new Promise((r,rj) => {
console.log('外p');
r();
}).then(() => {
console.log('外then1');
new Promise(((r,rj) => {
console.log('内p');
r();
})).then(() => {
console.log('内then1');
return new Promise((r, rj) => {r();});
}).then(() => {
console.log('内then2');
});
}).then(() => {
console.log('外then2');
}).then(() => {
console.log('外then3');
}).then(() => {
console.log('外then4');
});
// return new Promise((r, rj) => {r();}) 等同于
// return new Promise((r, rj) => {r();}).then(()=>{console.log(1)}).then(()=>{console.log(2)}).then(()=>{console.log(3)});
// 执行结果:外p,外then1,内p,内then1, 外then2,外then3,外then4,内then2,
例子19:
const p1 = new Promise( (resolve,reject) => {
setTimeout(() => {
reject(new Error('fail'))
console.log('3s') // console.log语句仍然会执行,并且在reject()异步函数 前执行
},3000)
})
const p2 = new Promise( (resolve,reject) => {
setTimeout( () => {
return resolve(p1) // 一般都在这里加return,这样后面的代码就不会执行,防止意外!!
console.log('1s')
}, 1000 )
})
p2.then(res => console.log(res)) // 并没有执行
.catch(error => console.log(error))
// 打印结果:3s,Error:fail
// 注意: p2.then(res => console.log(....))并没有执行,因为p2的状态变成了p1的状态,是rejected
// p2.then(res => console.log(res,'fulfilled'), res => console.log(res,'rejected'))
// 实际执行的是上面的 第二个回调函数
链接:https://www.jianshu.com/p/81df186ea7f1