欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用 Promise

程序员文章站 2022-05-06 11:37:54
...

目录

1.Promise是什么. Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值.

首先来听一个故事,有一个名为 createAudioFileAsync() 的函数,如果给出一些配置和两个回调函数,这个函数能异步地生成音频文件。一个回调函数是文件成功创建时的回调,另一个则是出现异常时的回调。

看起来就是这样他就是改了个样子,Promise 是一个被某些函数传出的对象,我们附加回调函数(callback)使用它,而不是将回调函数传入那些函数内部。(这句话很绕口,意思就是写promise底层的是个函数,我们知道promise对象默认是要传进一个function的(

),但是这个function不是传给底层构造他的函数.而是在then()这个触发的时候调用的.总之,我看完后,觉得他真的像Node的事件模块.不过因为同步和异步的差别,他们执行的顺序还是有点差别,但是多次注册,以及多次触发,链式调用.真的写法上又有很大的相似.不过这两个还是不一样的.当然Node事件模块还是可以,调用promise的.这块待之后研究.)

2.约定(你可以先跳过这里,因为你最好在了解他的运行顺序再来看这里,这样你就会明白了)

3.api的讲解

1.链式调用promise.then()的语法

(当 Promise 变成接受状态(fulfilled)时调用的函数。该函数有一个参数,即接受的最终结果(the fulfillment  value)。如果该参数不是函数,则会在内部被替换为 (x) => x,即原样返回 promise 最终结果的函数)这段话真的很书面化,你根本不知道他说的是什么,然后我测试了下这个最终结构就是"foo",同理换成rejected就是错误的原因(UnhandledPromiseRejectionWarning: foo).这两个api后面讲真不行,你先跳过这里,但最好是硬着头皮,怀着疑问,然后在看完rejected和resolve后再来看这里.

到这里,你应该懂了,我前面说的他为什么和event模块这么像.原因在于promise就像注册一样.你一定要用触发函数去触发.then()是,setTimeout也是.所以按照这样分类,可以将promise模块分成两种一种是函数执行触发用的,一种是对promise进行拼接啥的,返回的还是promise,并且还可以和promise自己api函数进行调用.比如all的迭代.

2.Promise.resolve()和 Promise.reject()

1.Promise.resolve(value)

讲人话就是,then(....).resolve这样的写法.

2.Promise.reject(reason);

3. Promise.all(iterable);

4.Promise.race(iterable);

3. 时序

4.嵌套


蓝字是我的重点讲解.但是建议先看完白字.结合https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises

 

1.Promise是什么. Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值.

首先来听一个故事,有一个名为 createAudioFileAsync() 的函数,如果给出一些配置和两个回调函数,这个函数能异步地生成音频文件。一个回调函数是文件成功创建时的回调,另一个则是出现异常时的回调。

// 成功的回调函数
function successCallback(result) {
  console.log("音频文件创建成功: " + result);
}

// 失败的回调函数
function failureCallback(error) {
  console.log("音频文件创建失败: " + error);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback)

使用 Promise

函数 createAudioFileAsync() 被重写为返回 Promise 对象的形式

const promise = createAudioFileAsync(audioSettings);
promise.then(successCallback, failureCallback);


createAudioFileAsync(audioSettings).then(successCallback, failureCallback);

// createAudioFileAsync()  是一个`重写返回Promise对象的形式

使用 Promise

看起来就是这样他就是改了个样子,Promise 是一个被某些函数传出的对象,我们附加回调函数(callback)使用它,而不是将回调函数传入那些函数内部。(这句话很绕口,意思就是写promise底层的是个函数,我们知道promise对象默认是要传进一个function的(

new Promise( function(resolve, reject) {...} /* executor */  );

),但是这个function不是传给底层构造他的函数.而是在then()这个触发的时候调用的.总之,我看完后,觉得他真的像Node的事件模块.不过因为同步和异步的差别,他们执行的顺序还是有点差别,但是多次注册,以及多次触发,链式调用.真的写法上又有很大的相似.不过这两个还是不一样的.当然Node事件模块还是可以,调用promise的.这块待之后研究.)

 

2.约定(你可以先跳过这里,因为你最好在了解他的运行顺序再来看这里,这样你就会明白了)

3.api的讲解

p.then(onFulfilled[, onRejected]);

p.then(value => {
  // fulfillment
}, reason => {
  // rejection
});

1.链式调用promise.then()的语法

第一种语法:

Promise.resolve("foo")
// 1. 接收 "foo" 并与 "bar" 拼接,并将其结果做为下一个 resolve 返回。
    .then(function(string) {
        console.log(string)
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                string += 'bar';
                resolve(string);
            }, 1);
        });
    })
    // 2. 接收 "foobar", 放入一个异步函数中处理该字符串
    // 并将其打印到控制台中, 但是不将处理后的字符串返回到下一个。
    .then(function(string) {
        setTimeout(function() {
            string += 'baz';
            console.log(string);
        }, 1)
        return string;
    })
    // 3. 打印本节中代码将如何运行的帮助消息,
    // 字符串实际上是由上一个回调函数之前的那块异步代码处理的。
    .then(function(string) {
        console.log("Last Then:  oops... didn't bother to instantiate and return " +
            "a promise in the prior then so the sequence may be a bit " +
            "surprising");

        // 注意 `string` 这时不会存在 'baz'。
        // 因为这是发生在我们通过setTimeout模拟的异步函数中。
        console.log(string);
    });

Promise.reject("foo")
// 1. 接收 "foo" 并与 "bar" 拼接,并将其结果做为下一个 resolve 返回。
    .then(function(string) {
        console.log(string)
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                string += 'bar';
                resolve(string);
            }, 1);
        });

(当 Promise 变成接受状态(fulfilled)时调用的函数。该函数有一个参数,即接受的最终结果(the fulfillment  value)。如果该参数不是函数,则会在内部被替换为 (x) => x,即原样返回 promise 最终结果的函数)这段话真的很书面化,你根本不知道他说的是什么,然后我测试了下这个最终结构就是"foo",同理换成rejected就是错误的原因(UnhandledPromiseRejectionWarning: foo).这两个api后面讲真不行,你先跳过这里,但最好是硬着头皮,怀着疑问,然后在看完rejected和resolve后再来看这里.

这个链式写法,还要根据返回值.

  • 返回了一个值,那么 then 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
  • 没有返回任何值,那么 then 返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined
  • 抛出一个错误,那么 then 返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
  • 返回一个已经是接受状态的 Promise,那么 then 返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
  • 返回一个已经是拒绝状态的 Promise,那么 then 返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
  • 返回一个未定状态(pending)的 Promise,那么 then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。

测试吧,这个了解下就好了.

可以通过errormessage去获取信息.

Promise.resolve()
  .then(() => {
    // 使 .then() 返回一个 rejected promise
    throw new Error('Oh no!');
  })
  .then(() => {
    console.log('Not called.');
  }, error => {
    console.error('onRejected function called: ' + error.message);
  });

 

箭头函数简写

Promise.reject()
    .then(() => 99, reason => 42) // onRejected returns 42 which is wrapped in a resolving Promise
    .then(solution => console.log('Resolved with ' + solution)); 

了解下执行顺序

使用 Promise

如果 onFulfilled 返回了一个 promise,then 的返回值就会被 Promise resolved 或者 rejected。

function resolveLater(resolve, reject) {
    setTimeout(function() {
        resolve(10);
    }, 1000);
}
function rejectLater(resolve, reject) {
    setTimeout(function() {
        reject(new Error('Error'));
    }, 1000);
}

var p1 = Promise.resolve('foo');
var p2 = p1.then(function() {
    return new Promise(resolveLater);
});
var p3 = p1.then(function() {
    return new Promise(rejectLater);
});


p2.then(function(v) {
    console.log('resolved', v);
}, function(e) {
    // not called
    console.error('rejected', e);
});


p3.then(function(v) {
    // not called
    console.log('resolved', v);
}, function(e) {
    console.error('rejected', e);
});

在旧式回调 API 中创建 Promise

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

wait(10000).then(() => saySomething("10 seconds")).catch(failureCallback)

到这里,你应该懂了,我前面说的他为什么和event模块这么像.原因在于promise就像注册一样.你一定要用触发函数去触发.then()是,setTimeout也是.所以按照这样分类,可以将promise模块分成两种一种是函数执行触发用的,一种是对promise进行拼接啥的,返回的还是promise,并且还可以和promise自己api函数进行调用.比如all的迭代.

const promise = doSomething();
doSomething().then(function(result) {
    return doSomethingElse(result);
})
    .then(function(newResult) {
        return doThirdThing(newResult);
    })
    .then(function(finalResult) {
        console.log('Got the final result: ' + finalResult);
    })
    .catch(failureCallback);

dosomething = new Promise((resolve, reject) => {
    console.log('初始化');

    resolve();
})

上面的代码都是不正确的,只是一个逻辑.其中dosomething是需要new promise去构造的.return的都是promise对象.

就是一个链式的写法

catch的后续

new Promise((resolve, reject) => {
    console.log('初始化');

    resolve();
})
    .then(() => {
        throw new Error('有哪里不对了');

        console.log('执行「这个」”');
    })
    .then(
        ()=>{
            console.log("会不会被牵连?")
        }
    ).catch(() => {
        console.log('执行「那个」');
    })
    .then(() => {
        console.log('执行「这个」,无论前面发生了什么');
    });

通常,一遇到异常抛出,Promise 链就会停下来,直接调用链式中的 catch 处理程序来继续当前执行。这看起来和以下的同步代码的执行很相似。"会不会被牵连"就是那样的.

2.Promise.resolve()和 Promise.reject()

 

首先注意几点

1.Promise.resolve(value)

方法返回一个以给定值解析后的Promise 对象。如果该值为promise,返回这个promise;如果这个值是thenable(即带有"then" 方法))这将导致无限递归,因为它试图展平无限嵌套的promise。

讲人话就是,then(....).resolve这样的写法.

Promise.resolve(value);语法

返回一个解析过带着给定值的Promise对象,如果参数是一个Promise对象,则直接返回这个Promise对象。

value(1.将被Promise对象解析的参数。2.一个Promise对象 3.一个thenable。)

 

2.Promise.reject(reason);

reason:表示Promise被拒绝的原因。

返回值;一个给定原因了的被拒绝的 Promise

 

3. Promise.all(iterable);

iterable

一个可迭代对象,如 Array 或 String

Promise.all(iterable) 方法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);如果参数中  promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。

  • 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promise
  • 如果传入的参数不包含任何 promise,则返回一个异步完成(asynchronously resolved) Promise。注意:Google Chrome 58 在这种情况下返回一个已完成(already resolved)状态的 Promise
  • 其它情况下返回一个处理中(pending)Promise。这个返回的 promise 之后会在所有的 promise 都完成或有一个 promise 失败时异步地变为完成或失败。 见下方关于“Promise.all 的异步或同步”示例。返回值将会按照参数内的 promise 顺序排列,而不是由调用 promise 的完成顺序决定。
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, 'foo');
});

Promise.all([p1, p2, p3])
    .then(([r1, r2, r3]) => {console.log(r1);console.log(r1,r2,r3)});


这样单独传参.


var p1 = Promise.resolve(3);
var p2 = Promise.resolve(312);
var p3 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, 'foo');
});

[p1, p2, p3].reduce((p, f) => p.then(f), Promise.resolve(32)).then(result3 => { console.log(result3);})



const applyAsync = (acc,val) => acc.then(val);
const composeAsync = (...funcs) => x => funcs.reduce(applyAsync, Promise.resolve(x));
const transformData = composeAsync(func1, func2, func3);
const result3 = transformData(data);

砂锅面这两种需要比较下.

4.Promise.race(iterable);

iterable

可迭代对象,类似Array。详见 iterable

 

一个待定的 Promise 只要给定的迭代中的一个promise解决或拒绝,就采用第一个promise的值作为它的值,从而异步地解析或拒绝(一旦堆栈为空)。

race 函数返回一个 Promise,它将与第一个传递的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个。

 

3. 时序

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

wait().then(() => console.log(4));
Promise.resolve().then(() => console.log(2)).then(() => console.log(3));
console.log(1); // 1, 2, 3, 4

4.嵌套

doSomethingCritical()
.then(result => doSomethingOptional()
  .then(optionalResult => doSomethingExtraNice(optionalResult))
  .catch(e => {console.log(e.message)})) // 即使有异常也会忽略,继续运行;(最后会输出)
.then(() => moreCriticalStuff())
.catch(e => console.log("Critical failure: " + e.message));// 没有输出

到此为止promise 搞定了.

 

 

再来系统的看下...

 

一个 Promise有以下几种状态:

  • pending: 初始状态,既不是成功,也不是失败状态。
  • fulfilled: 意味着操作成功完成。
  • rejected: 意味着操作失败。

使用 Promise

Promise.prototype.constructor

返回被创建的实例函数.  默认为 Promise 函数.创建Promise

const myFirstPromise = new Promise((resolve, reject) => {
  // ?做一些异步操作,最终会调用下面两者之一:
  //
  //   resolve(someValue); // fulfilled
  // ?或
  //   reject("failure reason"); // rejected
});

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相关标签: Javascript学习