前言
- js是单线程执行的,一次只能干一件事;
- 遇到需要耗时的代码,那就先挂起,先执行不耗时的代码,等到不耗时的代码执行完了,v8腾出手了,再来执行耗时代码;
- Promise是JavaScript中用于处理异步操作的一种编程模式。
正文
同步/异步代码
同步代码
- 程序按照代码的顺序依次执行,每一行代码执行完毕后才会执行下一行代码,直到程序结束。在执行过程中,如果遇到需要等待的资源(如文件读写、网络请求等I/O操作),程序会阻塞当前线程,等待该操作完成后再继续执行后续代码;
- 在同步执行模式下,如果某个操作耗时较长,整个程序或当前任务就会暂停,无法进行其他操作,影响整体效率。
异步代码
- 允许程序在发起一个可能耗时的操作(如I/O操作)后,不等待其完成,而是继续执行下一条指令。当耗时操作完成后,会通过回调函数、事件、Promise、async/await等方式通知主线程或安排后续处理逻辑,这样程序在等待耗时操作的同时可以进行其他任务,提高了程序的响应性和执行效率;
- 异步编程避免了阻塞,使得应用在执行耗时操作时依然能够保持用户界面的流畅和其他任务的处理。
代码实例:
// 异步代码
function foo() {
setTimeout( () => {
console.log('ltt');
}, 1000)
}
// 同步代码
function bar() {
console.log('lxp');
}
foo();
bar();
分析:
- 上述代码先执行foo,再执行bar,但是foo设置了一个定时器,需要等待1s后才执行操作;
- foo代码部分为异步代码,bar代码部分为同步代码,异步代码不需要等待,所以先执行bar,等待1s后,再执行foo。
如果我就想按我给的代码顺序执行,那该怎么操作呢?
- 将同步代码的函数放到异步代码函数里面去调用执行
- 下面的代码就可以实现先执行函数a,再执行函数b
let data = {};
function a() {
setTimeout( () => { // ajax
data = { name: 'ltt'};
b();
}, 1000)
}
function b() {
console.log(data.name + '好美');
}
a();
使用回调函数的话,如果嵌套过深,一旦出现问题很难排查,所有引入Promise。
Promise
Promise构造函数
- 通过Promise来处理异步操作,实现将多个异步操作按照顺序依次执行;
- 通过每个Promise的
.then或.catch方法可以返回一个新的Promise来实现链式调用; - Promise构建一个实例时,接受两个参数:
resolve和reject,这两个参数的类型都为function。
resolve
此函数用于标记Promise已被成功解决(fulfilled)。当你调用resolve(value)时,你在告诉Promise它操作成功完成了,并且可以将value(一个返回的数据)传递给那些通过.then方法注册的回调函数。一旦resolve被调用,Promise的状态就会从pending(等待中)变为fulfilled(已成功),并且不能再改变。
rejecrt
此函数用于标记Promise已被拒绝(rejected),即操作失败了。当你调用reject(reason)时,你传递一个原因(通常是一个错误对象或错误信息字符串)来说明为什么会失败。这会导致Promise状态从pending(等待中)变为rejected(已失败),同样,状态一旦变为rejected就不能再改变。之后,所有通过.catch方法注册的回调将被执行,用来处理这个错误。
一个小实例--resolve-then
我想要通过代码来实现言覃相亲、结婚和生宝宝的步骤:
- 定义一个
函数xq(相亲),该函数内放了一个2s的定时器,在该函数设置resolve函数,表示已成功执行,并设置返回的value为相亲成功; - 定义一个
函数marry(结婚),该函数内放了一个1s的定时器,在该函数设置resolve函数,表示已成功执行,并设置返回的value为新婚快乐; - 定义一个
函数baby(生宝宝),该函数直接进行输出操作; - 执行
函数xq并在该函数后面接一个then(因为该函数设置了resolve),传入res(函数xq的resolve传入的value)并在该回调函数内进行输出同时返回函数marry的执行结果; - 再在后面接一个
then,传入res2(函数marry的resolve传入的value)并在该回调函数内进行输出同时执行函数baby。
代码:
function xq() {
return new Promise( (resolve, reject) => {
setTimeout( () => {
console.log('言覃相亲了!');
resolve('相亲成功'); // 成功
}, 2000)
})
}
function marry() {
return new Promise( (resolve, reject) => {
setTimeout( () => {
console.log('coconut marry!');
resolve('新婚快乐!');
}, 1000)
}
)
}
function baby() {
console.log('baby~');
}
xq().then( (res) => {
console.log(res);
return marry();
})
.then( (res2) => {
console.log(res2);
baby();
})
一个小实例--reject-catch
- 定义一个函数a,该函数内放了一个1s的定时器,先输出,然后放了一个reject函数,传入的err;
- 当函数a执行成功才可以执行b,执行失败则返回err。
function a() {
return new Promise(function(resolve, reject) {
setTimeout( () => {
console.log('a is ok');
reject('a');
}, 1000)
})
}
function b() {
console.log('b is ok');
}
a().then( (res) => {
b();
})
.catch((err) => {
console.log(err);
}
)
a().then( (res) => { b(); })可以简写为a().then(b)
Promise.race/all
Promise.race
- 用途:当你需要处理多个异步操作,但只关心其中最快完成的那个结果时,可以使用
Promise.race。
function a() {
return new Promise(function(resolve, reject) {
setTimeout( () => {
console.log('a is ok');
resolve('a');
}, 1000)
})
}
function b() {
return new Promise(function(resolve, reject) {
setTimeout( () => {
console.log('b is ok');
resolve('b');
}, 500)
})
}
function c() {
console.log('c is ok');
}
Promise.race([a(), b()]).then( () => {
c();
})
Promise.all
- 用途:当你需要并行执行多个独立的异步操作,并且所有操作都成功完成后才继续下一步操作时,使用
Promise.all非常合适。
function a() {
return new Promise(function(resolve, reject) {
setTimeout( () => {
console.log('a is ok');
resolve('a');
}, 1000)
})
}
function b() {
return new Promise(function(resolve, reject) {
setTimeout( () => {
console.log('b is ok');
resolve('b');
}, 500)
})
}
function c() {
console.log('c is ok');
}
Promise.all([a(), b()]).then( () => {
c();
}
)
结语
大家成功进军Promise了吗?冲冲冲!!!