继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Promise 概述

MYYA
关注TA
已关注
手记 438
粉丝 75
获赞 326

关于Promise

  • Promise实例一旦被创建就会被执行

  • Promise过程分为两个分支:pending=>resolvedpending=>rejected

  • Promise状态改变后,依然会执行之后的代码:

const warnDemo = ctx => {  const promise = new Promise(resolve => {
    resolve(ctx);    console.log("After resolved, but Run"); // 依然会执行这个语句
  });  return promise;
};

warnDemo("ctx").then(ctx => console.log(`This is ${ctx}`));

then方法

Console键入以下内容:

let t = new Promise(()=>{});
t.__proto__

可以看到,then方法是定义在原型对象Promise.prototype上的。

then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。

写法

function func(args) {    // 必须返回一个Promise实例
    return new Promise((resolve,reject)=>{        if(...){
            resolve(...) // 传入resolve函数的参数
        } else {            let err = new Error(...) 
            reject(err) // reject参数必须是Error对象
        }
    })
}

func(ARGS).then(()=>{    // resolve 函数},()=>{    // reject 函数})

连续调用then

因为then方法返回另一个Promise对象。当这个对象状态发生改变,就会分别调用resolvereject

写法如下:

func(ARGS).then(()=>{
    ...
}).then(    ()=>{ ... },
    () => { ... }
)

实例

function helloWorld(ready) {    return new Promise((resolve,reject)=>{        if (ready){
            resolve("Right") 
        } else {            let error = new Error("arg is false")
            reject(error) // 传入Error对象
        }
    })
}

helloWorld(false).then((msg)=>{ // true:helloWorld的参数
    // 参数msg:在上面的Promise对象中传入了
    console.log(msg)
},(error)=>{    console.log(error.message)
})

catch方法

等同于 .then(null, rejection)。另外,then方法指定的回调函数运行中的错误,也会被catch捕获。

所以,之前的写法可以改为:

function func(args) {    // 必须返回一个Promise实例
    const promise =  new Promise((resolve,reject)=>{        if(...){
            resolve(...) 
        } else {            let err = new Error(...) 
            reject(err) 
        }
    })    return promise
}

func(ARGS).then(()=>{    // resolve 函数}).catch(()=>{    // reject 函数}).then(()=>{    // 没有错误就会跳过上面的catch})...

finally方法

指定不管 Promise 对象最后状态如何,都会执行的操作。可以理解为then方法的实例,即在resolvereject里面的公共操作函数

all方法

用于将多个 Promise 实例,包装成一个新的 Promise 实例。它接收一个具有Iterator接口的参数。其中,item如果不是Promise对象,会自动调用Promise.resolve方法

以下代码:

const p = Promise.all([p1, p2, p3]); // p是新包装好的一个Promise对象

对于Promise.all()包装的Promise对象,只有实例的状态都变成fulfilled

可以用来操作数据库:

const databasePromise = connectDatabase();const booksPromise = databasePromise
  .then(findAllBooks);const userPromise = databasePromise
  .then(getCurrentUser);Promise.all([
  booksPromise,
  userPromise
])
.then(([books, user]) => pickTopRecommentations(books, user));

或者其中有一个变为rejected,才会调用Promise.all方法后面的回调函数。而对于每个promise对象,一旦它被自己定义catch方法捕获异常,那么状态就会更新为resolved而不是rejected

'use strict'const p1 = new Promise((resolve, reject) => {
    resolve('hello');
}).then(    result => result
).catch(    e => e
);const p2 = new Promise((resolve, reject) => {    throw new Error("p2 error")
}).then(    result => result
).catch( 
    // 如果注释掉 catch,进入情况2
    // 否则,情况1
    e => e.message
);Promise.all([p1, p2]).then(    result => console.log(result) // 情况1).catch(    e => console.log("error in all") // 情况2);

race方法

all方法类似,Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。而且只要有一个状态被改变,那么新的Promise状态会立即改变

也是来自阮一峰大大的例子,如果5秒内无法fetech,那么p状态就会变为rejected

const p = Promise.race([
  fetch('/resource-that-may-take-a-while'),  new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('request timeout')), 5000)
  })
]);
p.then(response => console.log(response));
p.catch(error => console.log(error));

重要性质

状态只改变一次

Promise 的状态一旦改变,就永久保持该状态,不会再变了。

下面代码中,Promise对象resolved后,状态就无法再变成rejected了。

'use strict'const promise = new Promise((resolve,reject)=>{
    resolve('ok') // 状态变成 resolved
    throw new Error("test") // Promise 的状态一旦改变,就永久保持该状态})
promise.then((val)=>{    console.log(val)
}).catch((error)=>{    console.log(error.message) // 所以,无法捕获错误})

错误冒泡

Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获

"吃掉错误"机制

Promise会吃掉内部的错误,并不影响外部代码的运行。所以需要catch,以防丢掉错误信息。

阮一峰大大给出的demo:

'use strict'const someAsyncThing = function() {    return new Promise(function(resolve, reject) {        // 下面一行会报错,因为x没有声明
        resolve(x + 2);
    });
};
  
someAsyncThing().then(function() {    console.log('everything is great');
});
  
setTimeout(() => { console.log(123) }, 2000);

还有如下demo

someAsyncThing().then(function() {  return someOtherAsyncThing();
}).catch(function(error) {  console.log('oh no', error);  // 下面一行会报错,因为y没有声明
  y + 2;
}).catch(function(error) {  console.log('carry on', error);
});// oh no [ReferenceError: x is not defined]// carry on [ReferenceError: y is not defined]

参考

  • demo基本可以在阮一峰的Es6讲解中找到,只是为了理解做了一些修改。

  • 还有网上的一些博客,这里就不一一说明了



作者:godbmw
链接:https://www.jianshu.com/p/f5fb8b3cf1b0


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP