因为JavaScript是单线程的,有一个致命问题是在某一时刻内只能执行特定的一个任务,并且会阻塞其它任务执行,为了解决这个问题,Javascript语言将任务的执行模式分成同步(Synchronous)和异步(Asynchronous),在遇到类似I/O等耗时的任务时js会采用异步操作,而此时异步操作不进入主线程、而进入"任务队列",只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行,这时就不会阻塞其它任务执行,而这种模式称为js的事件循环机制(Event Loop)。
promise
一、Promise对象有以下两个特点
(1)对象的状态不受外界影响
Promise对象代表一个异步操作,有三种状态:
- 进行中(pending): 初始状态,既没有被兑现,也没有被拒绝。
- 已成功(fulfilled): 意味着操作成功完成。resolve
- 已失败(rejected): 意味着操作失败。reject
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。不论在后面怎么调用then,实际上的异步操作只会被执行一次,多次调用没有效果。
Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。
只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。即已经resolve或reject。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。Promise无法取消,一旦新建它就会立即执行,无法中途取消。
const promise = new Promise(function(resolve, reject) {})
// resolve函数的作用是,将Promise对象的状态从'未完成'变为'成功'
//(即从 pending 变为 fulfilled),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去.
// reject函数的作用是,将Promise对象的状态从'未完成'变为'失败'(即从 pending 变为 rejected)
//在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去.
二、基本使用
const promise = new Promise(function(resolve, reject) {
if (/* 异步操作成功 */) {
resolve(value)
} else {
reject(error)
}
})
// Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
// 这两个函数都是可选的,不一定要提供。它们都接受Promise对象传出的值作为参数。
promise.then(function(value) {
// success
// 第一个回调函数是Promise对象的状态变为resolved时调用
}, function(error) {
// failure
// 第二个回调函数是Promise对象的状态变为rejected时调用
})
三、方法
const p = Promise.all([p1, p2, p3])
onst p = Promise.any([p1, p2, p3])
async-await
1、async
async 函数返回的是一个 Promise 对象、所以在最外层不能用 await 获取其返回值的情况下,我们当然应该用原来的方式:then() 链来处理这个 Promise 对象,就像这样
async function timeout() {
return 'hello world'
}
timeout().then(result => {
console.log(result);
})
console.log('虽然在后面,但是我先执行');
现在回过头来想下,如果 async 函数没有返回值,又该如何?很容易想到,它会返回 Promise.resolve(undefined)。
联想一下 Promise 的特点——无等待,所以在没有 await 的情况下执行 async 函数,它会立即执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。这和普通返回 Promise 对象的函数并无二致。那么下一个关键点就在于 await 关键字了。
2、await
1)为什么要用await:为了使我们的异步代码,更像同步的代码
2)因为 async 函数返回一个 Promise 对象,所以 await 可以用于等待一个 async 函数的返回值——这也可以说是 await 在等 async 函数,但要清楚,它等的实际是一个返回值。注意到 await 不仅仅用于等 Promise 对象,它可以等任意表达式的结果,所以,await 后面实际是可以接普通函数调用或者直接量的。
3)不管await后面的代码是同步还是异步,await总是需要时间,从右向左执行,先执行右侧的代码,执行完后,发现有await关键字,于是让出线程,阻塞代码
4)注意await 关键字只能放到async 函数里面
5)await的后面需要是一个Promise对象,如果不是则会被转成Promise对象。只要其中一个如果Promise对象变为reject状态,那么整个async函数都会中断操作。如果状态是resolve,那么他的返回值则会变成then里面的参数,最好把await放入try{}catch{}中
如何使用
function takeLongTime() {
return new Promise(resolve => {
setTimeout(() => resolve("long_time_value"), 1000);
});
}
async function test() {
try{
const v = await takeLongTime();
console.log(v);
}
catch {
.....
}
}
test();
rxjs、promise区别
promise 代码
let promise = new Promise( (resolve) => {
setTimeout(() => {
resolve('chen');
},2000)
});
promise.then((value) => {
console.log(value);
})
Rxjs代码
let start = new Observable( (observer) => {
let timeOut = setTimeout( () => {
observer.next('chen2');
},4000)
})
let str = start.subscribe( (value) => {
console.log(value);
})
区别1: rxjs可以取消subscribe,promise不可以
setTimeout( () => {
str.unsubscribe();
},1000)
区别2: rxjs可以发射多次,promise只能发射一次
let setTime2;
let start2 = new Observable( (observable) => {
let count = 0;
setTime2 = setInterval( () => {
observable.next(count++);
},1000)
})
let str2 = start2.subscribe( (num) => {
console.log(num);
if(num > 10){
str2.unsubscribe();
clearInterval(setTime2);
}
})
区别3: rxjs 自带了许多的工具函数,如filter等