Promise
异步处理解决方案
- 支持链式调用,解决回调地狱(不断回调缩进,可读性差,不好维护,不好异常处理)
- 错误处理更加方便
const p = new Promise((resolve, reject)=>{
setTimeout(function(){
let data = '用户数据'
// resolve(data);
let err = '失败'
reject(err);
}, 1000);
});
p.then(function(value){
console.log(value)
}, function(reason){
console.error(reason)
});
then
返回结果是个Promise,状态由回调函数执行结果决定
若return一个非promise类型的值,状态就为成功,对象的PromiseValue为返回值(没有return相当于返回undefined)
若return一个promise类型,状态为return的promise的状态
若throw错误,为失败
p.then(()=>{ //成功时的回调
},()=>{ //失败时的回调
});
链式调用
p.then(value=>{
}).then(value=>{
})
catch
catch错误
p.catch(function(reason){
});
promisify方法
传入一个以错误优先的回调函数
(err, value)=>{
}
状态
promise实例对象的属性:PromiseState
- pending
- resolved / fullfilled //成功
- rejected //失败
pending只能改为resolved或者rejected,且只能改变一次
对象的值
PromiseResult:保存对象【成功/失败】的结果
下面两个函数可以更改该值:
- resolve
- reject
工作流程
- 成功了,改变状态值,执行then中第一个回调函数
- 失败了,改变状态值,执行then中第二个回调函数
API
构造函数
Promise(excutor){}
- executor函数 执行器
(resolve, reject)=>{} //立即执行
- resolve函数 内部定义成功调用的函数
value=>{}
- reject函数 内部定义失败调用的函数
reason=>{}
then方法
(onResolve, onRejected)=>{}
catch方法
失败的回调
(onRegected)=>{}
resolve方法
不是实例对象
Promise.resolve(521)
// 返回promise对象
参数是个Promise,返回的状态由Promise参数状态决定
参数为一个非promise类型的值,返回的状态就为成功,对象的PromiseValue为参数值(没有参数相当于undefined)
reject方法
不是实例对象
返回失败的promise对象
all方法
不是实例对象
参数:promise数组
返回一个新promise,所有promise成功则成功,结果为输入的promise的结果的数组;否则失败,结果值为失败promise结果的数组。
race方法
不是实例对象
参数:promise数组
返回一个新promise,结果由第一个完成的结果状态决定
关键问题
如何改变promise状态
- resolve
- reject
- 抛出错误
throw '出问题了';
promise指定多个成功/失败回调函数,都会调用?
当状态改变时,都会调用
改变状态和指定回调函数谁先谁后执行?
都有可能
- 当是同步任务,立即执行resolve时,先改变状态,后执行then;或延迟更长时间才调用then()
- 当是异步任务,不会立即执行时,后执行resolve改变状态先执行then
执行then只是指定回调函数,不是执行回调函数,执行回调函数永远等改变了状态再执行。若先改变状态后指定,指定时立即执行。
then方法返回的新promise的结果状态由什么决定?
- 若抛出异常,新promise变为reje,reason为抛出的异常
- 若返回的是非promise的任意值,新promise变为resolved,value为返回的值
- 若返回的是另一个新promise,此promise的结果会变成新promise的结果
如何串联多个操作任务
let p = new Promise((resolve, reject)=>{
});
p.then(value => {
return new Promise((resolve, reject)=>{
});
}).then(value => {
})
异常穿透
当then链式调用时,可以在最后指定失败的回调,前面任何操作出现异常,都会传到最后失败的回调中处理
中断promise链?
在回调函数中返回一个pendding状态的promise对象
p.then(value => {
return new Promise(()=>());
})
手写Promise
promise.js
function Promise(executor) {
this.PromiseState = 'pending';
this.PromiseResult = null;
this.callbacks = [];
const self = this;
function resolve(data) {
if (self.PromiseState !== 'pending') return;
//修改对象状态
self.PromiseState = 'fulfilled';
//设置对象结果
self.PromiseResult = data;
setTimeout(()=>{
self.callbacks.forEach(item => {
item.onResolved();
});
});
}
function reject(data) {
if (self.PromiseState !== 'pending') return;
//修改对象状态
self.PromiseState = 'rejected';
//设置对象结果
self.PromiseResult = data;
setTimeout(()=>{
self.callbacks.forEach(item => {
item.onRejected();
});
})
}
// 同步调用执行器函数
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
if (typeof onResolved !== 'function') {
onResolved = value => value;
}
if (typeof onRejected !== 'function') {
onRejected = reason => {
throw reason;
}
}
return new Promise((resolve, reject) => {
function callback(type){
try {
let result = type(self.PromiseResult);
if (result instanceof Promise) {
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
resolve(result);
}
} catch (e) {
reject(e);
}
}
if (this.PromiseState === 'fulfilled') {
setTimeout(()=>{
callback(onResolved)
});
}
if (this.PromiseState === 'rejected') {
setTimeout(()=>{
callback(onRejected)
})
}
if (this.PromiseState === 'pending') {
this.callbacks.push({
onResolved: function() {
callback(onResolved)
},
onRejected: function() {
callback(onRejected)
}
});
}
})
}
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected);
}
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(v=>{
resolve(v);
}, r=>{
reject(r);
});
} else {
resolve(value);
}
})
}
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason);
})
}
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
let count = 0;
let arr = [];
for (let i = 0; i < promises.length; i++) {
promises[i].then(v=>{
count++;
arr[i] = v;
if (count === promises.length) {
resolve(arr);
}
}, r => {
reject(r);
})
}
});
}
Promise.race = function(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(v => {
resolve(v);
}, r => {
reject(r);
})
}
})
}
PromiseClass.js
class Promise {
constructor(executor) {
this.PromiseState = 'pending';
this.PromiseResult = null;
this.callbacks = [];
const self = this;
function resolve(data) {
if (self.PromiseState !== 'pending') return;
//修改对象状态
self.PromiseState = 'fulfilled';
//设置对象结果
self.PromiseResult = data;
setTimeout(() => {
self.callbacks.forEach(item => {
item.onResolved();
});
});
}
function reject(data) {
if (self.PromiseState !== 'pending') return;
//修改对象状态
self.PromiseState = 'rejected';
//设置对象结果
self.PromiseResult = data;
setTimeout(() => {
self.callbacks.forEach(item => {
item.onRejected();
});
})
}
// 同步调用执行器函数
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onResolved, onRejected) {
const self = this;
if (typeof onResolved !== 'function') {
onResolved = value => value;
}
if (typeof onRejected !== 'function') {
onRejected = reason => {
throw reason;
}
}
return new Promise((resolve, reject) => {
function callback(type) {
try {
let result = type(self.PromiseResult);
if (result instanceof Promise) {
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
resolve(result);
}
} catch (e) {
reject(e);
}
}
if (this.PromiseState === 'fulfilled') {
setTimeout(() => {
callback(onResolved)
});
}
if (this.PromiseState === 'rejected') {
setTimeout(() => {
callback(onRejected)
})
}
if (this.PromiseState === 'pending') {
this.callbacks.push({
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
}
});
}
})
}
catch (onRejected) {
return this.then(undefined, onRejected);
}
static resolve(value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(v=>{
resolve(v);
}, r=>{
reject(r);
});
} else {
resolve(value);
}
})
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
})
}
static all(promises) {
return new Promise((resolve, reject) => {
let count = 0;
let arr = [];
for (let i = 0; i < promises.length; i++) {
promises[i].then(v=>{
count++;
arr[i] = v;
if (count === promises.length) {
resolve(arr);
}
}, r => {
reject(r);
})
}
});
}
static race(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(v => {
resolve(v);
}, r => {
reject(r);
})
}
})
}
}
async函数
返回值为promise对象,结果由asnc执行的返回值决定
async function main() {
// 1. 非promise,返回成功的promise
return 123;
// 2. 是promise,返回相同结果的promise
return new Promise((resolve, reject)=>{
reject("error");
});
// 3. 抛出异常,返回失败的promise,结果为抛出的结果
throw "oh no";
}
let result = main();
await表达式
await右侧表达式一般为promise对象。若表达式是promise对象,await返回的是promise成功的值。若表达式是其他值,直接将此值作为await的返回值。
- await必须写在async函数中,但async函数中可以没有await
- 若await的promise失败,就会抛出异常,需要通过try…catch捕获异常
async function main(){
let p = new Promise((resolve, reject)=>{
resolve("OK");
});
let res = await p;
console.log(res);
}
main();
async与await
const fs = require('fs');
const util = require('util');
const myReadFile = util.promisify(fs.readFile);
async function main(){
let data1 = await myReadFile('./1.html')
let data2 = await myReadFile('./2.html')
let data3 = await myReadFile('./3.html')
console.log(data1 + data2 + data3);
}
代码
util.promisify.js
const util = require('util');
const fs = require(fs);
let mineReadFile = util.promisify(fs.readFile);
mineReadFile('./1.html').then(value=>{
});
promise读取文件.js
const fs = require('fs');
const p = new Promise(function(resolve, reject){
fs.readFile('../js笔记.md', (err, data)=>{
if (err) reject(err);
resolve(data);
});
});
p.then(function(value){
console.log(value.toString());
}, function(reason){
console.log("读取失败!");
})
promise读取多个文件.js
const fs = require('fs');
const p = new Promise((resolve, reject)=>{
fs.readFile('./a.md', (err, data)=>{
resolve(data);
});
});
p.then(value=>{
return new Promise((resolve, reject)=>{
fs.readFile('./b.md', (err, data)=>{
resolve([value, data]);
});
});
}).then(value=>{
return new Promise((resolve, reject)=>{
fs.readFile('./c.md', (err, data)=>{
resolve([...value, data]);
});
});
}).then(value=>{
console.log(value.join('\r\n'));
})
promise封装Ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function sendAjax(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
}
});
}
sendAjax('').then(function (value) {
console.log(value);
}, function (reason) {
console.log(reason);
})
</script>
</body>
</html>
async_await封装Ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 200px;
height: 200px;
border: solid 3px pink;
}
</style>
</head>
<body>
<button>Send</button>
<div></div>
<script>
function sendAjax(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
}
});
}
let btn = document.querySelector('button');
let div = document.querySelector('div');
btn.addEventListener('click', async function(){
let sendPromise = await sendAjax('http://127.0.0.1:8000/server');
div.innerHTML = sendPromise;
});
</script>
</body>
</html>