Promise

Promise

同步&异步

JavaScript的执行环境是单线程

单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会阻塞其他任务。这个任务可称为主线程。

但实际上还有其他线程,如事件触发线程、ajax请求线程等,这也就引发了同步和异步的问题。

同步

同步模式,即上述所说的单线程模式,一次只能执行一个任务,函数调用后需等到函数执行结束,返回执行的结果,才能进行下一个任务。如果这个任务执行的时间较长,就会导致线程阻塞

var x = true;
while(x);
console.log("don't carry out");    //不会执行

上面的例子即同步模式,其中的while是一个死循环,它会阻塞进程,因此第三句console不会执行。
同步模式比较简单,也较容易编写。但问题也显而易见,如果请求的时间较长,而阻塞了后面代码的执行,体验是很不好的。因此对于一些耗时的操作,异步模式则是更好的选择。

异步

异步模式,即与同步模式相反,可以一起执行多个任务,函数调用后不会立即返回执行的结果,如果任务A需要等待,可先执行任务B,等到任务A结果返回后再继续回调。

setTimeout(function() {
    console.log('taskA, asynchronous');
}, 0);
console.log('taskB, synchronize');
//while(true);

-------ouput-------
taskB, synchronize
taskA, asynchronous

定时器延时的时间明明为0,但taskA还是晚于taskB执行。这是为什么呢?由于定时器是异步的,异步任务会在当前脚本的所有同步任务执行完才会执行。如果同步代码中含有死循环,即将上例的注释去掉,那么这个异步任务就不会执行,因为同步任务阻塞了进程。

回调函数

提起异步,就不得不谈谈回调函数了。上例中,setTimeout里的function便是回调函数。可以简单理解为:(执行完)回(来)调(用)的函数。

In computer programming, a callback is a piece of executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at some convenient time.

翻译:回调函数是一段可执行的代码段,它以「参数」的形式传递给其他代码,在其合适的时间执行这段(回调函数)的代码。

The invocation may be immediate as in a synchronous callback, or it might happen at a later time as in an asynchronous callback.

翻译:回调函数不仅可以用于异步调用,一般同步的场景也可以用回调。在同步调用下,回调函数一般是最后执行的。而异步调用下,可能一段时间后执行或不执行(未达到执行的条件)。

/******************异步回调******************/
function request(url, param, successFun, errorFun) {
    $.ajax({
        type: 'GET',
        url: url,
        param: param,
        async: true,    //默认为true,即异步请求;false为同步请求
        success: successFun,
        error: errorFun
    });
}
request('test.html', '', function(data) {
    //请求成功后的回调函数,通常是对请求回来的数据进行处理
    console.log('请求成功啦, 这是返回的数据:', data);
},function(error) {
    console.log('sorry, 请求失败了, 这是失败信息:', error);
});

为什么使用Promise

Promise对象是用于异步操作的。

function sendRequest(url, param) {
    return new Promise(function (resolve, reject) {
        request(url, param, resolve, reject);
    });
}

sendRequest('test.html', '').then(function(data) {
    //异步操作成功后的回调
    console.log('请求成功啦, 这是返回的数据:', data);
}, function(error) {
    //异步操作失败后的回调
    console.log('sorry, 请求失败了, 这是失败信息:', error);
});

其实,Promise的真正强大之处在于它的【多重链式调用】,可以避免层层嵌套回调。如果我们在第一次ajax请求后,还要用它返回的结果再次请求呢?

request('test1.html', '', function(data1) {
    console.log('第一次请求成功, 这是返回的数据:', data1);
    request('test2.html', data1, function (data2) {
        console.log('第二次请求成功, 这是返回的数据:', data2);
        request('test3.html', data2, function (data3) {
            console.log('第三次请求成功, 这是返回的数据:', data3);
            //request... 继续请求
        }, function(error3) {
            console.log('第三次请求失败, 这是失败信息:', error3);
        });
    }, function(error2) {
        console.log('第二次请求失败, 这是失败信息:', error2);
    });
}, function(error1) {
    console.log('第一次请求失败, 这是失败信息:', error1);
});

以上出现了多层回调嵌套,有种晕头转向的感觉。这也就是我们常说的厄运回调金字塔(Pyramid of Doom),又叫"回调地狱"。编程体验十分不好。而使用Promise,我们就可以利用then进行「链式回调」,将异步操作以同步操作的流程表示出来。

sendRequest('test1.html', '').then(function(data1) {
    console.log('第一次请求成功, 这是返回的数据:', data1);
}).then(function(data2) {
    console.log('第二次请求成功, 这是返回的数据:', data2);
}).then(function(data3) {
    console.log('第三次请求成功, 这是返回的数据:', data3);
}).catch(function(error) {
    //用catch捕捉前面的错误
    console.log('sorry, 请求失败了, 这是失败信息:', error);
});

Promise的基本用法

基本用法

Promise对象代表一个未完成、但预计将来会完成的操作。
它有以下三种状态:

  • pending:初始值,不是fulfilled,也不是rejected
  • fulfilled:代表操作成功
  • rejected:代表操作失败

Promise有两种状态改变的方式,既可以从pending转变为fulfilled,也可以从pending转变为rejected。一旦状态改变,就「凝固」了,会一直保持这个状态,不会再发生变化。当状态发生变化,promise.then绑定的函数就会被调用。
注意:Promise一旦新建就会「立即执行」,无法取消。这也是它的缺点之一(可通过将其封装进函数,当需要时在调用函数来解决此问题)。

var promise = new Promise(function (resolve, reject) {
    if (/* 异步操作成功 */) {
        resolve(data);
    } else {
        /* 异步操作失败 */
        reject(error);
    }
});

使用new来构建一个Promise

Promise接受一个「函数」作为参数,该函数的两个参数分别是resolvereject。这两个函数就是就是「回调函数」,由JavaScript引擎提供。

  • resolve函数的作用:在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。
  • reject函数的作用:在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise实例生成以后,可以用then方法指定resolved状态和reject状态的回调函数。

promise.then(onFulfilled, onRejected);

promise.then(function(data) {
  // do something when success
}, function(error) {
  // do something when failure
});

then方法会返回一个Promise。

它有两个参数,分别为Promise从pending变为fulfilledrejected时的回调函数(第二个参数非必选)。

这两个函数都接受Promise对象传出的值作为参数
简单来说,then就是定义resolvereject函数的,其resolve参数相当于:

function resolveFun(data) {
    //data为promise传出的值
}

而新建Promise中的’resolve(data)’,则相当于执行resolveFun函数。

Promise新建后就会立即执行。

then方法中指定的回调函数,将在当前脚本所有同步任务执行完才会执行

var promise = new Promise(function(resolve, reject) {
  console.log('before resolved');
  resolve();
  console.log('after resolved');
});

promise.then(function() {
  console.log('resolved');
});

console.log('outer');

-------output-------
before resolved
after resolved
outer
resolved

由于resolve指定的是异步操作成功后的回调函数,它需要等所有同步代码执行后才会执行,因此最后打印’resolved’。

完整原文链接:初探Promise

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值