学习异步与Promise

同步与异步

同步(Synchronous)

同步可以直接拿到结果

简单的例子来说,同步就是在学校食堂吃饭,必须要排队打饭,在打到饭之前都不能离开去做其他事情。

用计算机的语言来解释就是同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果。是一种线性执行的方式,执行的流程不能跨越。

异步(Asynchronous)

异步不能直接拿到结果,需要后续通过轮询或者回调的方法来得到结果

简单的例子来说,异步就是在网红饭店改善生活时,可以在在手机上取号后,就去逛街买奶茶干其他的事情,当手机上通知到你时再去就餐。

用计算机的语言来解释只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕;而是继续执行下面的流程。是一种并行处理的方式。

JS是单线程的

学习Java时,Java中可以通过开启多线程来完成异步操作,但是JS是单线程的是怎样执行异步任务的呢?

JS是单线程的,是指在浏览器的JS引擎中负责解释和执行JavaScript代码的线程只有一个,所以我们所写的JS代码在JS引擎中都是排队(同步)执行的。但很多时候关于I/O设备的操作要比闪电般的JS引擎慢很多,比如鼠标键盘的操作、网络请求……JS引擎中遇到这样的任务就很容易导致后续其他任务阻塞的问题,所以需要异步执行JS代码中的这些任务,咋异步呢?

多线程的浏览器就来帮忙啦,直接甩出三个大招(API),分别是 DOM Binding(DOM绑定)、network(网络请求)、timer(定时器)模块。

如果JS代码中的任务是属于这三个模块,浏览器就会判断它为异步任务,然后JS引擎中一遇到异步任务,浏览器就会把异步任务相关回调添加到任务队列中(异步任务必须要有回调函数),等待主线程的任务执行完毕,再执行任务队列中的任务。

这种运行机制称为Event Loop(事件循环)

(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。

(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。

(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。

(4)主线程不断重复上面的第三步。

Promise

上面介绍了JS中需要异步,Promise就是ES6中异步编程的一种解决方案

为什么需要Promise?

以往我都使用jQuery封装的Ajax来发送网络请求,当网络请求十分复杂时就会出现回调地狱

上图中回调得到的数据很容易混淆,且代码就十分难看且不容易维护,所以我们需要更优雅的方式来进行异步操作

Promise的使用

第一步

创建一个promise对象、可以使用new来调用Promise的构造器来进行实例化

return new Promise((resolve,reject)=>{
     // 异步处理
    // 处理结束后、调用resolve 或 reject
})
  • 任务成功时调用resolve(成功) 任务失败时调用reject(失败)

  • resolve 和 reject 都只接受一个参数

第二步

第一步构造出来的promise对象,含有一个 .then() 函数属性使用promise.then() 实例方法,设置其值在 resolve(成功) / reject(失败)时调用的回调函数

promise.then(onFulfilled, onRejected)
  • resolve(成功)时

    onFulfilled 会被调用

  • reject(失败)时

    onRejected 会被调用

举例

使用promise来发送网络请求

function getURL(URL) {
    return new Promise(function (resolve, reject) {
        var req = new XMLHttpRequest();
        req.open('GET', URL, true);
        req.onload = function () {
            if (req.status === 200) {
                resolve(req.responseText);
            } else {
                reject(req.statusText));
            }
        };
        req.onerror = function () {
            reject(req.statusText));
        };
        req.send();
    });
}
var URL = "http://xxx";
getURL(URL).then(function onFulfilled(value){
    console.log(value);
},function onRejected(error){
    console.log(error);
});

Promise还有更高级的用法,链式调用等等,以后在进行总结~

参考

JavaScript 运行机制详解:再谈Event Loop

并发模型与事件循环MDN

JavaScript Promise迷你书(中文版)