觉得promise没问题的可以直接挑战最后的测试题哦
Promise是JS中进行异步编程的新解决方案;promise对象用来封装一个异步操作并可以获取其成功或失败的结果
优点:
原来处理异步是纯回调,相比原来的优势:原来处理异步编程,在为执行异步的时候就需要指定回调函数;而promise可以在异步执行完再指定回调
指定回调函数的方式更加灵活: 可以在请求发出甚至结束后指定回调函数
支持链式调用, 可以解决回调地狱问题
原始纯回调:
var fs = require("fs");
fs.readFile("./src/a.txt", "utf-8", function (err, data) {
if (err) {
throw err;
}
console.log(data);
fs.readFile("./src/b.txt", "utf-8", function (err, data) {
if (err) {
throw err;
}
console.log(data);
fs.readFile("./src/c.txt", "utf-8", function (err, data) {
if (err) {
throw err;
}
console.log(data);
});
});
});
promise的写法:
new Promise(function (resolve, reject) {
fs.readFile("./src/a.txt", "utf-8", function (err, data) {
if (err) {
reject(err);
}
console.log(data);
resolve();
});
})
.then(() => {
fs.readFile("./src/b.txt", "utf-8", function (err, data) {
if (err) {
throw err;
}
console.log(data);
});
})
.then(() => {
fs.readFile("./src/c.txt", "utf-8", function (err, data) {
if (err) {
throw err;
}
console.log(data);
});
})
.catch((err) => {
console.log(err);
});
缺点:
一旦新建就会立即执行,中途无法取消
如果不设置回调函数,则内部抛出的错误不会反应到外部
处于pending状态时,无法知道目前进展到哪一阶段
三种状态:
pending :未确定的,起始状态
resolved (fulfilled) :成功的,调用了resolve()后的状态
rejected :失败的,调用了reject()后的状态
状态改变:
pending=>resolved
pending=>rejected
特点:
1>对象的状态不受外界影响,只有异步任务的结果可以决定当前的状态
2>一旦状态发生改变,就不会再次变了
修改promise状态的三种方法
1》调用resolve方法
2》调用reject方法
3》抛出异常 throw
const p = new Promise((resolve, reject) => {
// 1》调用resolve, pending --> resolved
// resolve(1); // resolved 1
// 2》调用reject, pending --> rejected
// reject(2); // rejected 2
// 3》抛出异常, pending --> rejected
throw 3; // rejected 3
});
p.then(
(value) => console.log("resolved", value),
(reason) => console.log("rejected", reason)
);
throw和reject() 都可以将promise状态变为rejected状态,但是throw抛出异常后,后面的代码是不会执行了的;这里是和throw的正常使用是一样,这里抛出的错误,.catch是能够捕获到的
new Promise()接收一个执行器函数,这个函数是一个立即执行的回调函数,执行器函数中接收两个方法,reject和resolve方法,它们是修改promise的状态的;如果调用其中一个,就会修改promise状态,,promise状态修改,就会调用对应的then或catch中的onResolved,onRejected回调函数
// 1 构造一个poromise实例对象
const p = new Promise((resolve, reject) => {
// 同步的执行器函数
// 2执行异步任务
setTimeout(() => {
// 3.1如果异步操作成功,promise的状态变为resolved,执行resolve函数
if (Math.random() > 0.5) {
resolve(11111);
} else {
// 3.2如果异步操作失败,promise的状态变为rejected,执行reject函数
reject(22222);
}
}, 0);
});
// 4 通过then或catch拿到结果
p.then((val) => console.log(val)).catch((reason) => console.log(reason));
大概的执行过程:
1》创建promise对象(pending),指定执行器函数,执行器函数是一个立即执行的同步任务
2》在执行器函数中启动异步任务
3》根据异步结果做不同处理:如果成功,调用resolve(),指定成功的value,promise状态变为resolved; 如果失败,调用reject()函数,指定失败的reason,promise状态变为rejected
4》指定成功或失败的回调函数来获取成功的value或失败的reason
then中可以接收两个回调,一个成功,一个失败,但是我们一般不这么写
执行器函数是一个同步任务,.then和catch中的回调函数是一个异步任务(微任务)
简单地使用promise包装ajax请求
function getAsyncRequest(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = () => JSON.parse(resolve(xhr.responseText));
xhr.onerror = () => JSON.parse(reject(xhr.statusText));
xhr.send();
});
}
getAsyncRequest("https://www.testapi.com").then((res) =>
console.log(res)
).catch((error) => console.log(error));
改变promise状态和指定回调函数谁先谁后?
不一定,都有可能;正常情况是先指定回调,再改状态;但是也有可能是先改状态,再指定回调;
指定回调是 .then或 .catch ;改变状态是调用resolve,reject或抛出异常
1》先指定回调,后改状态
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
});
}).then((value) => console.log(value));
2》先改状态,后指定回调
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
});
});
setTimeout(() => {
p.then((value) => console.log(value));
}, 2000);
const p = new Promise((resolve, reject) => {
resolve(1);
}).then((value) => console.log(value));
作用:为promise实例添加状态改变时的回调函数
返回值:返回一个新的Promise对象,因此可以使用链式写法
基本语法使用:
new Promise((resolve, reject) => {
setTimeout(() => {
reject(1);
});
}).then(
(value) => console.log(value),
(reason) => console.log(reason)
);
参数:接收两个回调函数作为参数,第一个是变为resolved状态的回调,第二个是变为rejected状态的回调;一般我们只是用第一个参数,另一个回调写在catch中
then中返回的promise:上一个回调函数完成后,将返回结果作为参数传入下一个回到函数
1》如果上一个函数返回一个正常值:将执行成功的回调,拿到的值就是上一个函数的返回值
2》如果上一个函数返回一个promise:
返回resolved状态的promise — 执行成功的回调onResolved()
返回rejected状态的promise — 执行失败的回调onRejected()
3》如果上一个函数抛出异常:执行 失败的回到onRejected()
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
});
})
p.then((value) => {
console.log("resolve1", value); // resolve1 1
return value; // 返回一个resolved状态的promise对象,结果为1
})
.then((val) => console.log("resolve2", val)) // resolve2 1;返回resolved状态promise
.then((v) => {
console.log("resolve3", v); // resolve3 undefined
return Promise.resolve(3); // 返回一个resolved状态的promise对象,结果为3
})
.then((value) => {
console.log("resolve4", value); // resolve3 3
return Promise.reject(4);// 返回一个rejected状态的promise对象,结果为4
})
.catch((reason) => {
console.log("reject4", reason); // reject4 4
throw 5; // 抛出异常,返回了一个rejected状态的promise,结果为5
})
.then((v) => {console.log(v)})
.catch((err) => console.log("reject5", 5)); // reject5 5
promise.then()返回的新promise的结果状态由什么决定?
由执行函数中的异步任务执行结果决定
1)如果抛出异常,新promise变为rejected ;reason为抛出异常(抛出什么,后面then中reason就等于什么)
2)如果返回的是非promise的任意值,新promise变为resolved,value为返回的值(后面then中value为return出来的值)
3)如果返回的是另一个新的promise,此promise的结果就为新promise的结果
如何中断promise链
返回一个pending状态的promise
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
});
})
.then((value) => {
console.log("resolve1", value); // resolve1 1
return new Promise(() => {
console.log("我没有调用resolve和reject函数,状态一直时pending");
});
})
.then((val) => console.log("resolve2", val)) // 不会打印
.catch((err) => console.log("reject5", 5)); // 不会打印
因为then中返回了一个promise对象,他的执行器函数为一个空的对象,既没有调用resolve()函数,也没有调用reject()函数,返回的时一个pending状态的promise实例对象,所以不会继续执行后面的then或catch中回调函数
一个promise指定多个成功/失败回调函数, 都会调用吗?
成功就调用所有成功的回调,失败就调用所有失败的回调,只是成功和失败的回调同时都调用:
const p = new Promise((resolve, reject) => {
resolve(1);
});
p.then(
(value) => console.log("resolved1", value),
(reason) => console.log("rejected1", reason)
);
p.then(
(value) => console.log("resolved2", value),
(reason) => console.log("rejected2", reason)
);
作用:指定发生错误是的回调,
返回值:返回一个新Promise对象
相当于
.then(null,onRejected)
promise状态变为rejected就会执行catch中的回调,另外then中抛出错误也会被catch捕获
如果Promise状态已经发生改变,再抛出错误是无效的,改变promise状态的reject()的作用等同于抛出异常
如果没有使用catch方法指定错误处理的回调,Promise对象抛出的错误不会传递到外层的代码,即不会由任何反应
promise错误穿透
为什么catch中的回调在最后还会执行呢?
如果then只指定了resolved状态的回调,相当于另一个采用默认的抛出异常,异常值为前面promise的结果;因为抛出异常,then会返一个失败的promise,后面的回调同样的,到最后catch前的还是一样,catch中的回调最终就会执行
new Promise((resolve, reject) => {
setTimeout(() => {
reject(1);
});
})
.then(
(value) => console.log(value)
// (reason) => {
// throw reason;
// return Promise.reject(reason);
// }
)
.then((value) => console.log(value))
.catch((err) => console.log(err));
参数如果不是一个对象,或不是具有then方法的对象,返回一个resolved状态的的Promise对象
const p1 = Promise.resolve(222);
// 等同于
const p2 = new Promise((resolve, reject) => {
resolve(222);
});
如果参数是一个Promise实例,那么Promise.resolve()不做任何处理,原封不动返回实例
const p2 = new Promise((resolve, reject) => {
resolve(222);
});
const p1 = Promise.resolve(p2); // 有一点像 p1= p2
如果参数是一个具有then方法的对象,会先就对象变为promise对象,然后立即执行then方法
返回一个rejected状态的promise对象,和resolve类似
将多个Promsie包装成一个新的Promise实例
const p = Promise.all([p1,p2,p3])
1> 只有当p1 p2 p3状态都变为resolved,p的状态才会变为resolved,此时p1 p2 p3 返回值组成一个数组,传递给p的回调函数
2> 只要当p1 p2 p3中有一个变为rejected,p的状态就会变为rejected,此时第一个被rejected的实例的返回值传递给p的回调函数
如果作为参数的Promise实例自身定义了catch方法,那么他被rejected时并不会触发Promise.all或race的catch方法
// 如果p3,P4都有catch,那么不会走到Promise.all中的catch,如果没有catch,但是状态又是rejected,就会走到catch中,而且只有最先执行完的那个失败的值
const p3 = new Promise((resolve, reject) => {
// resolve(3);
resolve(3);
})
.then((val) => val)
.catch((reason) => reason);
const p4 = new Promise((resolve, reject) => {
// resolve(4)
reject(4);
})
.then((val) => val)
.catch((reason) => reason);
Promise.all([p3, p4])
.then((val) => console.log(val))
.catch((reason) => console.log(reason));
最后一个catch是Promise.all()包装生成的Promise对象的onRejected回调
const p = Promise.race([p1,p2,p3])
只要 p1 p2 p3 中一个状态发生改变,p 的状态就跟着发生改变,最先变的Promise实例的返回值会传递给p的回调函数
不管是then还是catch方法结尾,最后一个地方抛出的错误都无法捕捉到,因为Promise内部的错误不会冒泡到全局
捕捉任何可能出现的错误,并向全局抛出
try {
new Promise((resolve, reject) => {
reject(1);
})
.catch((reason) => {
console.log(errTest); //ReferenceError: errTest is not defined
})
.done();
} catch (err) {
console.log("捕获到错误"); //捕获到错误
}
接收一个普通函数,无论如何都会执行,和 try … catch 中的finally差不多
new Promise((resolve, reject) => {
resolve(2);
})
.then((value) => {
throw 3;
})
.finally(function () {
console.log("all is over"); // 会打印 all is over
});
捕获不到的原因:try…catch只能捕获到同步错误
最后的打印结果是?
请耐心一点,本文精华都浓缩在这道题中了
const p = new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
resolve(2);
console.log(3);
}, 0);
});
console.log(4);
p.then((value) => {
console.log(value);
})
.then(() => {
return new Promise((resolve, reject) => {
throw 5;
console.log(6);
});
})
.then((value) => {
console.log(value);
})
.catch((reason) => console.log(reason))
.then((val) => console.log(val))
.then(() => {
return new Promise((resolve, reject) => {
resolve(8);
console.log(9);
reject(10);
}).then(
(value) => {
console.log(value);
},
(reason) => {
console.log(reason);
}
);
});
p.then((val) => {
console.log(val);
})
.then((v) => {
return new Promise(() => {});
})
.then((value) => {
console.log(11);
})
.catch((err) => console.log(err));
Promise.reject(7).catch((reason) => console.log(reason));
你的答案是什么呢?