Promise

本文介绍了JavaScript中的Promise,用于处理异步操作。Promise有三种状态:pending、resolved和rejected。它提供了then和catch方法进行链式调用,处理异步操作的结果。当then的回调函数返回值或抛出错误时,会影响返回的Promise状态。Promise.all()等待所有Promise完成,而Promise.race()则在第一个Promise决议时结束。未处理的异常可能会被吞掉,建议在每个Promise链的末尾添加catch。此外,async/await是Promise的语法糖,简化了异步代码的编写。
摘要由CSDN通过智能技术生成

同步异步

JavaScript 是单线程的,在发出一个调用之后 没有得到结果之前该调用就不返回,这种模式就是同步
所谓异步,就是调用在发出之后就直接返回了,调用者不会阻塞 可以继续执行后续操作,而被调用者执行得到结果后通过状态、事件来通知调用者使用回调函数来处理结果。

异步解决方案–Promise

基础介绍

Promise 对象是一个构造函数,用来生成promise实例。Promise表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值。— MDN-Promise

异步操作的三种状态:

  • pending
  • resolved:异步操作成功由 pending 变为 resolved
  • rejected:异步操作失败pending 变为 rejected
var p1 = new Promise(function(resovle) { ... }); 
console.log(p1)
// Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: "resolve"}
// Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: "reject"}

then、catch

Promise构造函数的原型上有一个then方法,它接受两个函数作为参数,分别是 resolved 状态和 rejected 状态的回调函数。
这两个回调函数接受的参数分别是Promise实例中resolve函数和reject函数中的参数。 另外rejected状态的回调函数是可省略的。

// 1
var p = new Promise(function(resolve, reject) { // Promise构造函数
    if (Math.random() < 0.5) {
        resolve('终值'); // resolved
    } else {
        reject('据因'); // rejected
    }
});

p.then(
    function(value){  // onResolved
        console.log(value);
    },
    function(reason){ // onRejected
        console.log(reason);
    }
);

Promise.resolve提供了一个简便的方法来得到接受的promise

Promise.resolve('resolve');
// 和上面接近等价
new Promise(function(resovle) { resovle('resolve') });

注意Promise实例在生成后会立即执行,而 then 方法只有在所有同步任务执行完后才会执行,看看下面的例子:

// 2
const promise = new Promise((resolve, reject) => {
    console.log('async task begins!');
    setTimeout(() => {
        resolve('done, pending -> resolved!');
    }, 1000);
})

promise.then(value => {
    console.log(value);
})

console.log('1.please wait');
console.log('2.please wait');
console.log('3.please wait');
// async task begins!
// 1.please wait
// 2.please wait
// 3.please wait
// done, pending -> resolved!
链式调用 then 方法

then 方法会返回一个新的 Promise 实例,可以分两种情况来看:

  • 指定返回值是新的 Promise 对象,如return new Promise(…),这种情况没啥好说的,由于返回的是 Promise,后面显然可以继续调用then方法。
  • 返回值不是Promise, 如:return 1 这种情况还是会返回一个 Promise,并且这个Promise 立即执行回调 resolve(1)。所以仍然可以链式调用then方法。(注:如果没有指定return语句,相当于返回了undefined)
// 3
var p1 = new Promise(function(resolve, reject) {
    if (Math.random() < 0.5) {
        resolve('resolve'); // resolve
    } else {
        reject('reject'); // reject
    }
});

var p2 = p1.then(
    function(value) {  // onResolved
        console.log(value);
        return 42;
        // return new Promise(function(resolve) {
        //     resolve(42);
        // });
        // return new Promise.reject(42)
    },
    function(reason){ // onRejected
        console.log(reason);
        return 21
    }
);

p2.then(function(value) {
    console.log('p2-resolve')
    console.log(value); // 42 或是 21
}, function(reason) {
    console.log('p2-reject')
    console.log(reason); // 不会执行
})

总结

  • 如果then中的回调函数返回一个值,那么then返回的Promise将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
  • 如果then中的回调函数抛出一个错误,那么then返回的Promise将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
  • 如果then中的回调函数返回一个已经是接受状态的Promise,那么then返回的Promise也会成为接受状态,并且将那个Promise的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
  • 如果then中的回调函数返回一个已经是拒绝状态的Promise,那么then返回的Promise也会成为拒绝状态,并且将那个Promise的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
    *如果then中的回调函数返回一个未定状态(pending)的Promise,那么then返回Promise的状态也是未定的,并且它的终态与那个Promise的终态相同;同时,它变为终态时调用的回调函数参数与那个Promise变为终态时的回调函数的参数是相同的。
被吞掉的异常

以下代码会造成ReferenceError,然而没有处理。

// 3
new Promise(function(resolve, reject) {
  resolve(a.b); // 运行后会提示 Uncaught (in promise) ReferenceError: a is not defined
  // reject('123'); // 提示 Uncaught (in promise) 123
})
.then(function(v) {
  console.log(v);
});

被拒绝的promise如果没有catch处理控制台会提示错误信息,但是不影响代码段继续执行,这就是被吞掉的异常。被吞掉的异常较难察觉,无法记录,因此推荐所有的promise最后都加上catch。

new Promise(function(resolve, reject) {
    resolve(a.b);
    // reject('123');
})
    .then(function(v) {
        console.log(v);
    })
    .catch(function(err) {
        console.error(err);
        //ReferenceError: a is not defined
        //123
    });
Promise.all([])

Promise.all返回一个promise,只有在传入Promise.all所有promise都完成, 返回的promise才会完成,并且其终值为所有promise的终值组成的数组。 如果有任何promise被拒绝,你只会得到第一个拒绝promise的结果。 这种模式被称为门: 只有所有人都到齐,门才会开。

let p1 = new Promise((resolve, reject) => {
    resolve('成功了')
})

let p2 = new Promise((resolve, reject) => {
    resolve('success')
})

let p3 = Promise.reject('失败')

Promise.all([p1, p2]).then((result) => {
    console.log(result)               //['成功了', 'success']
}).catch((error) => {
    console.log(error)
})

Promise.all([p1, p2, p3]).then((result) => {
    console.log(result)
}).catch((error) => {
    console.log(error)      // 失败了,打出 '失败'
})
Promise.race([])

对于Promise.race来说,返回的promise只取决于只有第一个被决议的promise, 并且其结果和被决议的promise相同。这种模式被称为门闩:第一个到达者,打开门闩。

// 5
var p1 = Promise.resolve('resolve--p1');
var p2 = 1337; // 参数不是promise时, 表示解决
var p3 = new Promise((resolve, reject) => {
    setTimeout(function() {
        resolve('resolve--p3')
    });
});
Promise.race([p1, p2, p3]).then(value => {
    console.log(value); // resolve--p1
});

// 加入被拒绝的promise
var p4 = Promise.reject('reject--p4');
Promise.race([p1, p2, p3, p4]).then(value => {
    console.log(value); // resolve--p1
});

Promise.race([p4, p1, p2, p3]).then(value => {
    console.log(value);
}).catch(error => {
    console.log(error); // reject--p4
})

注意:如果Promise.race被传入空数组会被挂住,永远不会被决议,而Promise.all会立即完成。

async/await实际上是Generator的语法糖。
顾名思义,async关键字代表后面的函数中有异步操作,await表示等待一个异步方法执行完成。声明异步函数只需在普通函数前面加一个关键字async即可,如:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值