天天看点

异步编程promise-async-await-rxjs

因为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等