JavaScript是一门单线程语言,不支持多线程,是从上往下一行一行执行的同步任务,这就意味着没法使用多线程来同时处理多个任务,但是js中存在任务队列,当主程序执行完之后,会轮训任务队列依次执行,这也是我们学习的异步任务,使用Promise实现异步操作。
同步:同一时间只能做一个任务;
异步:同一时间做多个任务。
比如:定时器就是异步任务,当程序解读到定时器时,不管定时的时间有多短,它都会被系统抛到任务队列中等侯,等到主程序任务执行完毕,任务队列会依次把定时器再抛回主程序执行。
setTimeout(() => {
console.log("宏任务1");
}, 0)
console.log("主程序同步任务1");
pending:进行中
fulfilled:已成功
rejected:已失败
resolved:表示已定型。当状态有pending到fulfilled还是pengding到rejected,只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。
Promise的特点:
Promise:对象的状态不受外界影响。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
Promise:一旦状态改变,就不会再变,任何时候都可以得到这个结果
Promise是一个构造函数,需要实例化。这个构造函数的参数是一个函数,该函数接收两个参数。
let p1 = new Promise((resolve, reject) => {
// 成功
resolve();
// 失败
// reject();
});
实例化对象之后,通过then方法分别指定resolved状态和rejected状态的回调函数。
参数1是resolved状态的回调函数;参数2是rejected状态的回调函数,这个参数是可选的,一般用catch方法捕获错误信息,后面会介绍的。
p1.then(result => result, resaon = resaon)
完整的链式操作:
let p1 = new Promise((resolve, reject) => {
// 成功
// resolve();
// 失败
reject();
}).then(success => {
console.log("成功的业务处理 1");
}, fail => {
console.log("失败拒绝的业务处理");
}).then(success => {
console.log("成功的业务处理 2");
}, fail => {
console.log("失败拒绝的业务处理");
});
第一个then方法是处理上面的Promise实例,同时返回一个新的Promise实例对象,第二个then方法是对该新Promise对象的处理,默认是resolved状态,所以是成功的。
Promise的队列是微任务队列,定时器、函数等是宏任务队列。微任务队列同样是等主程序任务执行完成后再执行。
整个顺序是:主任务 、微任务队列、宏任务队列。
setTimeout(() => {
console.log("宏任务1");
}, 0)
console.log("主程序同步任务1");
new Promise((resolve, reject) => {
//这里面的代码是同步任务
console.log("Promise中的同步任务");
// 只有success和fail的执行是微任务,也就是对应着then方法的执行放到微任务队列中
// then方法的代码只有在接收到成功或失败的信号时才会执行
resolve(); // 它的位置不影响任务是主程序还是微任务 放到第一行显示还是一样的
}).then(result => {
console.log("成功微任务1");
}, reason => {
console.log("失败微任务2");
})
注释里有很清楚的解释。
console.log("主1");
new Promise(resolve => {
// 程序走到这时,是主程序的同步任务
// 遇到定时器时,把它放入到宏任务当中,等到主程序和微任务执行完
setTimeout(() => {
console.log("setTimeout");
// 此时把任务成功失败的标志写在定时器里时就不同了
// 这就代表整个程序只有主任务和宏任务了,主任务执行完之后,开始执行宏任务setTimeout
// 整个定时器会被抛到主任务中,当定时器的所有任务执行完之后(输出setTimeout),才会把resolve抛给微任务
// 主程序执行完了,接着执行微任务 输出成功
resolve(); // 输出: 主1 setTimeout 成功
}, 0);
// resolve(); // 输出: 主1 成功 setTimeout
}).then(reslove => {
console.log("成功");
})
then方法是处理Promise实例对象的两个状态的回调函数。
then方法实质上也是一个Promise对象,它执行过后返回一个新的Promise对象。
在多个then方法链式调用时,第二个then方法是对第一个then方法处理完Promise返回的新Promise对象的回调函数,依次类推。
let p1 = new Promise((resolve, reject) => {
// 成功
resolve("成功的业务处理 1");
});
let p2 = p1
.then( // 这个then是处理上一个promise
success => console.log(success),
fail => console.log(fail)
) // 下面的then方法默认是对成功状态处理,自动走成功的函数
.then(
success => console.log("success"),
fail => console.log(fail)
);
在then中也可以返回一个新的Promise实例对象,则其后面紧接着的then方法是对返回的新Promise的处理。
// Promise后面的then方法是对前面一个Promise的处理.
new Promise((resolve, reject) => {
reject("处理失败了");
})
.then(null, reson => {
console.log(reson);
// 返回了一个Promise,下面接着的then方法就是对这个返回的Promise做处理
return new Promise((resolve, reject) => {
// resolve("成功处理.....");
reject("失败了........")
}) // 处理上面的promise
.then(null,
reason=> {
console.log(reason);
// 下面没有then方法 这个新的Promise实例对象返回出去
return new Promise((resolve, reject) => {
reject("最终还是失败了");
});
});
})
// 是对最里面返回的Promise做处理. 一个Promise对应一个then. 下一个then是一个新的Promise
.then(
res => console.log(res),
reson => console.log("error: " + reson)
)
then方法的两个参数中的第二个参数是可选的,是Promise状态为rejected的回调函数,通常我们不使用它,使用catch() 方法捕获错误信息。
let p1 = new Promise((resolve, reject) => {
reject("失败了");
})
.then(success => {
console.log("成功的业务处理 1");
})
.catch(error => console.log(new Error(error)))
该方法把多个Promise实例包装成一个新的Promise对象。
方法返回的实例的状态取决于 : 率先变换状态的那个Promise实例。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
// Promise.race()方法 返回的是参数实例状态率改变的那个
// 哪个返回的快 使用哪个
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p1成功")
}, 5000)
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error("request timeout"))
// resolve("p2的2秒")
}, 2000)
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p3的3秒")
}, 3000)
});
const p = Promise.race([p1, p2, p3])
.then(result => console.log(result))
.catch(error => console.log(error));
最先状态改变的是p2,2秒。所以Promise.race() 返回的是p2的状态同时接收p2的返回值作为回调函数的参数。
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。
new Promise((resolve, reject) => {
reject("error")
}).finally(() => {
console.log("不管怎样 都会执行");
}).catch(error => error)
把现有的对象变为Promise实例对象的方法。
参数的形式有四种:
// 1. Promise实例
const promise = new Promise((resolve, reject) => {
resolve("promise实例本身");
}).then(res => console.log(res));
console.log(promise); // 返回实例本身
const obj = {
then: function (resolve, reject) {
resolve("带then方法的对象");
}
};
const objPromise = Promise.resolve(obj)
.then(res => console.log(res))
// console.log(objPromise); // 返回Promise实例,并执行源对象的then方法
// 3.不带then方法的对象或者原始值
const originNum = Promise.resolve("hello");
originNum.then(res => console.log(res))
console.log(originNum);
// 4. 没有参数
const nullParams = Promise.resolve();
console.log(nullParams);
方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
参数会原封不动的传给实例对象的rejected的回调函数。
const selfReject = Promise.reject("错误程序");
selfReject.then(null, reason => console.log(reason));
console.log(selfReject);
把多个Promise实例包装成一个新的Promise对象,接收多个Promise实例对象。返回对应的状态处理结果。
const p = Promise.all([p1,p2,p3)
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,
此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,
此时第一个被reject的实例的返回值,会传递给p的回调函数。
补充一点:若参数实例有自己的catch捕获错误,最终那个实例catch之后的对象是一个新的Promise对象,默认会走成功,
所以,最后带有自己的catch的实例返回状态是resolved
分别测试下这几种情况:
所以Promise实例对象全部返回resolved
const p1 = new Promise((resolve, reject) => {
resolve("p1成功");
});
const p2 = new Promise((resolve, reject) => {
resolve("p2成功"); //1
});
const p3 = new Promise((resolve, reject) => {
resolve("p3成功"); //1
});
const p = Promise.all([p1, p2, p3])
.then(result => {
console.log(result);
})
.catch(error => {
console.log(new Error(error));
})
三个Promise实例都是resolve,所以p结果的状态也是resolve,同时返回参数的返回值。
至少有一个Promise对象返回rejected
const p1 = new Promise((resolve, reject) => {
reject("p1失败"); // 2
});
const p2 = new Promise((resolve, reject) => {
// resolve("p2成功"); //1
reject("p2失败") // 2
// throw new Error("p2失败"); // 2
});
const p3 = new Promise((resolve, reject) => {
resolve("p3成功"); //1
});
const p = Promise.all([p1, p2, p3])
.then(result => {
console.log(result);
})
.catch(error => {
console.log(new Error(error));
})
其中有两个Promise实例的状态有pending变为rejected,则p就为rejected,同时这个实例的返回值返回给p的回调函数。
Promise实例对象中有的存在自己的catch方法
const p1 = new Promise((resolve, reject) => {
resolve("p1成功"); // 1
});
const p2 = new Promise((resolve, reject) => {
reject("p2失败") // 2
// throw new Error("p2失败"); // 2
})
.then(result => result)
.catch(error => error);
const p3 = new Promise((resolve, reject) => {
resolve("p3成功"); //1
});
const p = Promise.all([p1, p2, p3])
.then(result => {
console.log(result);
})
.catch(error => {
console.log(new Error(error));
})
这里要注意,p2有自己的catch方法捕获rejected,所以p接收的p2这个Promise实例,是p2调用catch方法之后返回的一个新的Promise实例对象,该实例对象默认为resolved,所以会走then方法的第一回调函数,故p最终也能接收到由三个resolved的返回值组成的数组。
方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束。
方法最终的返回值是数组,每个成员对应一个传入Promise.allSettled()的 Promise 实例。每个对象都有status属性,该属性的值只可能是字符串fulfilled或字符串rejected。fulfilled时,对象有value属性,rejected时有reason属性,对应两种状态的返回值。
此方法能够保证传入的所有Promise操作结束.
因为这个方法会保证参数Promise实例对象全部完成后,不管是resolved还是rejected,方法才会返回,并且是fulfilled。
const p1 = new Promise((resolve, reject) => {
resolve("p1成功");
});
const p2 = new Promise((resolve, reject) => {
// resolve("p2成功"); //1
reject("p2 fail")
});
const p3 = new Promise((resolve, reject) => {
resolve("p3成功"); //1
});
const p = Promise.allSettled([p1, p2, p3]);
p.then(results => {
console.log(results);
});
封装异步加载图片的函数。
function loadImageAscy(src) {
return new Promise(function (resolve, reject) {
const img = new Image();
img.onload = function () {
resolve("加载成功");
}
img.onerror = function () {
reject(new Error("Couled not load images ar " + src));
}
img.src = src;
document.body.appendChild(img);
})
};
loadImageAscy("./bianhua.JPG").then(resolve => {
console.log(resolve);
});
emmmm,看了文档,看了视频,练习了这些方法。着实是有点多啊,还有的方法我没有写出来,我就挑出来感觉比较常用的几个。
加油!!!