JavaScript中的异步模式,我知道的都在里面了


前言:JS是单线程的语言,这意味着它同一时间只能做一件事,当碰到比较耗时的事情的时候,所有后面等待执行的任务就都得原地等待,为了解决这一问题,出现了异步,而异步的执行机制是主线程发送一个异步请求给相应的工作线程,然后主线程去处理其他事情,等到工作现成完成后,浏览器内部的线程会把工作线程的回调函数推入主线程的消息队列,最后主线程执行回调,完成异步操作。

一、Callback

1)Callback 函数的调用在一定程度上是不受我们的控制的,我们缺少可靠的机制确保回调函数能按照预期被执行。
2)难以理解(回调地狱)

二、Promise

是一个对象,从它可以获取异步操作的消息
特点:
1) 对象的状态不受外界影响。有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected
缺点:
1) 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
2) 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
3) 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

let promise = new Promise(function(resolve, reject) {
    console.log('Promise');
    if (true){
        resolve('2313');
    } else {
        reject('2313');
    }
    //执行错误,会跳过
    console.log('loaded');
});
promise.then(function() {
    console.log('resolved.');
    setTimeout(() => {
        console.log('in setTimeout');
    }, 0);
    new Promise(function(resolve){
        resolve('12');
    }).then(() => {
        console.log('in Promise');
        setTimeout(() => {
            console.log('in Promise setTimeout');
        }, 0);
    });
}).catch(function() {
    console.log('rejected.');
}).finally(function() {
    console.log('finally');
});

console.log('Hi!');
setTimeout(() => {
    console.log('out setTimeout');
}, 0);

then方法指定的回调函数,在当前脚本所有同步任务执行完才会执行
then/cath方法返回的是一个新的Promise实例

1、Promise.all

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的回调函数。
注意,如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。

const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result)
.catch(e => e);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]

2、Promise.race

const p = Promise.race([p1, p2, p3]);
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数

三、Generator

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();

调用 Generator 函数后,该函数并不执行,返回的是遍历器对象(Iterator Object)

必须调用遍历器对象的next方法,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。
yield表达式是暂停执行的标记,而next方法可以恢复执行。

yield表达式后面的表达式,只有当调用next方法才会执行

function* gen() {
  yield  123 + 456;
}

yield命令后面只能是 Thunk函数或 Promise对象

for...of循环可以自动遍历 Generator 函数运行时生成的Iterator对象,且此时不再需要调用next方法。

next返回值的 value 属性,是 Generator 函数向外输出数据;next方法还可以接受参数,向 Generator 函数体内输入数据。

1、Generator.prototype.throw()

Generator 函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获。

2、Generator.prototype.return()

Generator 函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历 Generator 函数。

• 函数可暂停和继续;
• 可返回多个值给外部;
• 在继续的时候,外面也可以再传入值;
• 通过 Generator 写的异步代码看起来就像是同步的;

四、Async

asyncawait
async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
async函数的返回值是 Promise 对象
async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

以上便是JavaScript中几种异步模式,有时候会被异步搞的乱七八糟,平常用的最多ajax请求,稍微有点不注意,就容易把异步忽略掉,小伙伴们把异步想像成一个脾气暴躁的小朋友,当你遇到他的时候跳过他,该干嘛干嘛去,等把自己的事情做完了,小朋友的脾气也消了,就能回来处理他了。
以上内容参考了沈老师的总结笔记,还有其他小伙伴的博客内容,有涉及侵权的请联系我删除。

发布了30 篇原创文章 · 获赞 6 · 访问量 4738

猜你喜欢

转载自blog.csdn.net/EcbJS/article/details/104700786