ホームページ  >  記事  >  ウェブフロントエンド  >  この記事 1 つで Promise を簡単にマスターできます

この記事 1 つで Promise を簡単にマスターできます

青灯夜游
青灯夜游転載
2023-02-10 19:49:162254ブラウズ

この記事 1 つで Promise を簡単にマスターできます

フロントエンド JS の学習において、誰もが最も不快に思うのは非同期問題です。非同期、コールバック地獄などの問題を解決するには、Promise を学習する必要があります。ほとんどのフロントエンドにとって、プログラマにとって、Promise は単なる悪夢です。この記事は、誰もが Promise を簡単に習得できるようにするための入り口として、わかりやすい観点から書かれています

非同期プログラミング


Promise を学びたい場合は、非同期プログラミングとは何かを理解する必要があります。ご存知のとおり、js 言語は シングルスレッドメカニズムです。いわゆるシングルスレッドとは、1 つのタスクを実行してから次のタスクを実行するという順序で実行することを意味します。ただし、2 つの操作の存在には影響しません: 同期 非同期 これら 2 つの操作は、実際には組立ライン (シングル スレッド) で実行されますが、これら 2 つの操作は、単一のスレッドです。実行順序が異なるだけです。 jsが非同期タスクをトリガーすると、その非同期タスクがブラウザに渡されて処理され、実行結果として非同期タスクのコールバック関数がキューの最後尾に挿入されて処理されます!

非同期を一般的な方法で説明しましょう: 非同期とは、タスク を完了するためにメイン スレッドからサブスレッドを起動することです。各タスクには 1 つ以上のコールバック関数があります ( callback ), 前のタスクが終了した後、次のタスクを実行する代わりに、コールバック関数 が実行されます。 後のタスクは、前のタスクの終了を待たずに実行されます。プログラムの実行 順序はタスクの順序と一致せず、非同期です。

この記事 1 つで Promise を簡単にマスターできます

この画像は、

Rookie の 非同期プログラミングから引用しました。チュートリアル セクション は、誰もが非同期とは何かをより深く理解するのに役立ちます。

#コールバック関数


コールバック関数の定義は非常に簡単です。関数は次のように扱われます。
実際のパラメータ

は別の関数 (外部関数 ) に渡され、この関数は外部関数内で呼び出され、特定のタスクを完了します。これは コールバック関数

コールバック関数を記述する 2 つの方法 (
効果は同じです

): <pre class="brush:js;toolbar:false;">const text = () =&gt; { document.write(&amp;#39;hello james&amp;#39;) } setTimeout(text,1000)</pre><pre class="brush:js;toolbar:false;">setTimeout(()=&gt;{ document.write(&quot;hello james&quot;) },1000)</pre>このコードでは

setTimeout

は時間がかかる処理です。最初のパラメータは callback function、2 番目のパラメータは ミリ秒数 です。この関数の実行後子スレッドが生成され、子スレッドは 1 秒待機してからコールバック関数 "text" を実行し、出力 hello jamessetTimeout が実行されます。テキスト内の子スレッドにあります。1 秒ほど待ちますが、メインスレッドの動作には影響しません。たとえば、次のコード:

setTimeout(()=>{
    document.write("hello davis")
},1000)
console.log(&#39;123456&#39;);

は、最初に
123456

(main thread) に出力され、次に hello が出力されます。 1 秒後のテキスト davis(subthread)

コールバック地獄

コールバック地獄という言葉はとても高尚に聞こえますが、Promise に連絡する前に、
コールバック地獄

とは何か、そしてなぜコールバック地獄が起こるのかを理解する必要があります。 まず概念を見てみましょう: コールバック関数をネストすると入れ子構造が現れ、入れ子関数が多すぎるとコールバック地獄が発生します

: たとえば、3 つの ajax リクエストを送信します。

最初のリクエストは通常​​どおり送信されます
  • 2 番目のリクエストは、次のように送信されます。 1 つが送信されます。 リクエストには、パラメータとして最初のリクエストの結果からの特定の値が必要です。
  • 3 番目のリクエストには、パラメータとして 2 番目のリクエストの結果からの特定の値が必要です。
次のコードが表示されます

:

$.ajax({
  url: &#39;我是第一个请求&#39;,
  type: &#39;get&#39;,
  success (res) {
    // 现在发送第二个请求
    $.ajax({
      url: &#39;我是第二个请求&#39;,
      type:&#39;post&#39;,
      data: { a: res.a, b: res.b },
      success (res1) {
        // 进行第三个请求
        $.ajax({
          url: &#39;我是第三个请求&#39;,
          type:&#39;post&#39;,
          data: { a: res1.a, b: res1.b },
                  success (res2) { 
            console.log(res2) 
          }
        })
      }
    })
  }
})

この種のコードは本当に厄介です。このようにコードを書くと、
保守性が悪い

という状態に陥ります。コードのエクスペリエンスが非常に悪く、しばらく見ていると混乱してしまいます。この問題を解決するために、 Promise では、Promise を使用してコールバック地獄の問題を解決します。

Promise

##Promise

非同期プログラミング Aソリューション これは、コールバック関数やイベントなどの従来のソリューションよりも合理的かつ強力です。これは ECMAScript 6 によって提供されるクラス であり、複雑な関数をよりエレガントに記述することを目的としています。 。 Promise オブジェクトには次の 2 つの特性があります:
オブジェクトの状態は外界の影響を受けません。 Promise オブジェクトは非同期操作を表し、

pending

(進行中)、

fulfilled
    (成功)、および
  • rejected

    (失敗) の 3 つの状態があります。 非同期操作の結果のみが現在の状態を決定でき、他の操作はこの状態を変更できません。これがプロミスの名前の由来でもあり、英語での意味は"約束"で、他の手段では変えられないという意味です。

  • 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

两个特点摘自于??阮一峰ES6文章

Promise语法格式

new Promise(function (resolve, reject) {
  // resolve 表示成功的回调
  // reject 表示失败的回调
}).then(function (res) {
  // 成功的函数
}).catch(function (err) {
  // 失败的函数
})

出现了new关键字,就明白了Promise对象其实就是一个构造函数,是用来生成Promise实例的。能看出来构造函数接收了一个函数作为参数,该函数就是Promise构造函数的回调函数,该函数中有两个参数resolvereject,这两个参数也分别是两个函数!

简单的去理解的话resolve函数的目的是将Promise对象状态变成成功状态,在异步操作成功时调用,将异步操作的结果,作为参数传递出去。reject函数的目的是将Promise对象的状态变成失败状态,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

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

代码示例:

        const promise = new Promise((resolve,reject)=>{
            //异步代码
            setTimeout(()=>{
                // resolve([&#39;111&#39;,&#39;222&#39;,&#39;333&#39;])
                reject(&#39;error&#39;)
            },2000)
        })
        promise.then((res)=>{
            //兑现承诺,这个函数被执行
            console.log(&#39;success&#39;,res);
        }).catch((err)=>{
            //拒绝承诺,这个函数就会被执行
            console.log(&#39;fail&#39;,err);
        })

代码分析:

上边说到Promise是一个构造函数,new之后等于说调用了构造函数,构造函数中传的参数是一个函数,这个函数内的两个参数分别又是两个函数(reslovereject),虽然感觉很绕,但是理清思路会很清晰的!


我们得到对象promise,promise对象中自带有两个方法thencatch,这两个方法中会分别再传入一个回调函数,这个回调函数的目的在于返回你所需要成功或失败的信息!那么怎么去调用这两个回调函数呢?
看下方图可以快速理解:

この記事 1 つで Promise を簡単にマスターできます
这两个函数分别做为参数(reslovereject)传到上方的函数中去了.随后在构造函数的回调函数中写入异步代码(例如:ajax定时器),这里使用了定时器作为例子,如果你想表达的是成功回调,你可以在内部调用函数reslove('一般情况下是后端返回的成功数据)。如果你想表达的是失败回调,你可以调用reject('一般情况下是后端返回的失败信息').

这些就是Promise执行的过程!虽然理解着很绕,但是多读几遍绝对有不一样的收获!

Promise链式

then方法返回的是一个新的Promise实例注意:不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法

实际案例:
我想要实现在一个数组中查看一个帖子,但是我最终的目的是得到这个帖子下面的所有评论,这该怎么实现呢?

实现思路
先从一个接口中获取这个帖子的信息,然后通过该帖子的帖子id从而获取到该帖子下的所有评论

代码如下:

pajax({
    url:"http://localhost:3000/news",
    data : {
        author : "james"
    }
}).then(res=>{
    return pajax({
        url : "http://localhost:3000/comments",
        data : {
            newsId : res[0].id
        }
    })
}).then(res=>{
    console.log(res);
}).catch(err=>{
    console.log(err);
})

代码分析:

这里使用了一个Promise已经封装过的ajax,我们从第一个接口中得到了帖子id,然后在then中的函数发送第二个请求(携带了第一个请求返回过来的参数),我们最后想要拿到第二个接口的结果,于是又有了一个then方法,但是在第一个then方法中要把一个新的Promise实例return出去,这样的话,第二个then才起作用!(这是因为then方法是Promise 实例所具有的方法,也就是说,then方法是定义在原型对象Promise.prototype上的)====>我们可以打印一下:console.log(Promise.prototype)

この記事 1 つで Promise を簡単にマスターできます
可以看的出来原型对象Promise.prototype中是有then方法的!

Promise.all()

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例

语法格式:

const p = Promise.all([p1, p2, p3]);

Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会调用Promise.reslove() [该方法可自行了解]自动将参数转为 Promise 实例,再进一步处理。

说那么多白话没用,我们可以根据一个案例,就可以明白Promise.all()的用途了。

实际案例:
如果你想实现一个效果:在一个页面中,等到页面中所有的请求返回数据后,再渲染页面,该怎么实现呢?(在实际开发中我们会看到loading加载页面,等数据返回完后,loading加载页面会消失,整个页面就展现出来了,增强用户的体验。)

实现思路:
通过Promise.all()方法,等多个接口全部接收到数据后,再统一进行处理,然后渲染页面

代码如下:

console.log("显示加载中")
const q1 = pajax({
    url:"http://localhost:3000/looplist"
})

const q2 = pajax({
    url:"http://localhost:3000/datalist"
})
Promise.all([q1,q2]).then(res=>{
    console.log(res)
    console.log("隐藏加载中...")
}).catch(err=>{
    console.log(err)
})

代码分析:

在上方代码中,全局打印显示加载中是代替loading的页面,表示该页面现在正是loading页面中,等到q1q2所请求接口都得到返回的信息后,在then方法中接收收据,并且可以进行渲染页面,同时隐藏了loading加载页面!

小结

不论是在前端的项目开发中还是在前端的面试过程中,Promise的地位就是举足轻重的,虽然解决异步编程的终极解决方案是async和await,但是它们也是基于Promise封装而来的,在以往文章中,我就说过,学习编程重要的是搞懂某个技术是怎么实现的,而不是做一个cv侠,多去思考,才能进步。继续加油吧,少年!

【相关推荐:javascript视频教程编程基础视频

以上がこの記事 1 つで Promise を簡単にマスターできますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。