settimeoutはコールバックのスタイル関数です.私たちがそれを変えるならば、何が起こりますか?



今日ではノードスタイルのコールバック関数を約束スタイル関数に変換するのが一般的です.それで、なぜ我々はこれをしませんでしたかsetTimeout ?
ノードスタイルコールバックの上で約束スタイル機能を好む主な理由は避けることですCallback Hell .

誰もそれを見たくない.
見た後setTimeout (兄弟姉妹だsetInterval or setImmediate ), 私は、それがcallbackスタイル機能であることをはっきりと見ることができます.
setTimeout(callback, 1000);
//         --------
//                 \
//                   See that? Right there. A callback!
しかし、誰でも変換するのを見ることはとても信じられないほどまれですsetTimeout コールバックから約束へ.どうやってsetTimeout レーダーの下で飛行?Is setTimeout 十分なパスを得るために?
ノーと言う.

ノードスタイルのコールバック関数

setTimeout 明らかにコールバックスタイル関数であっても、それは渡された可能性があります.
まず、ノードスタイルのコールバックを見てみましょう.fs.readFile ノードスタイルのコールバック関数の例です.
fs.readFile(path[, options], callback)
//                           --------
//                          /
//    callback must be last
コールバック自体は以下のようになります.
const callback = (err, data) => { /* ... */ }
//                ---  ----
//               /          \
//    error first             data last
If setTimeout 伝統的なノードスタイルのコールバック関数で、ノードのutil.promisify . ここではどのように簡単に使用するための例ですutil.promisify 改めるfs.readFile 約束スタイル機能に.
import fs from 'fs'
import { promisify } from 'util'

const readFile = promisify(fs.readFile)
残念ながらutil.promisify は動作しません.最初に、コールバックが最後の引数でないので.第二に、コールバックが(err, data) インターフェイス.

settimeoutの生成


幸い、これを手動で変換するだけで簡単です.新しい機能を呼びますsleep .
const sleep = milliseconds => value => new Promise (resolve =>
  setTimeout(() => resolve(value), milliseconds)
)
このコードに関していくつかの重要なことを指摘したい.
  • sleep がのろい.あなたは、なぜ理由が後でわかります.
  • sleep を取るvalue そして、value . 再び、あなたはなぜ後に表示されます.
  • 睡眠使用


    あなたのコードに一時停止を追加すると約束を使用して簡単です.
    const log => msg => console.log(msg)
    
    sleep(1000)('Hello World').then(log)
    
    それはすばらしいですが、私がこれを書いている理由ではありません.
    何が本当に私に興奮sleep 約束鎖の中央にそれをスリップする能力です.
    この例では、API呼び出しの間に1秒遅れを加えるのは些細なことでした.
    import axios from 'axios'
    import sleep from 'mojiscript/threading/sleep'
    
    const fetchJson = url => axios.get(url).then(response => response.data)
    const log = msg => (console.log(msg), msg)
    //                                  -
    //                                 /
    //     comma operator. google it.
    
    fetchJson('https://swapi.co/api/people/1')
      .then(log)
      .then(sleep(1000))
      .then(() => fetchJson('https://swapi.co/api/people/2'))
      .then(log)
      .then(sleep(1000))
      .then(() => fetchJson('https://swapi.co/api/people/3'))
      .then(log)
    
    だってsleep 入力として値をとり、同じ値を返します.sleep 基本的に約束チェーンミドルウェアになります.
    これをasync/waitのスタイルで書きましょう.
    import axios from 'axios'
    import sleep from 'mojiscript/threading/sleep'
    
    const fetchJson = url => axios.get(url).then(response => response.data)
    const log = msg => (console.log(msg), msg)
    
    const main = async () => {
      const people1 = await fetchJson('https://swapi.co/api/people/1')
      log(people1)
      await sleep(1000)
      const people2 = await fetchJson('https://swapi.co/api/people/2')
      log(people2)
      await sleep(1000)
      const people3 = await fetchJson('https://swapi.co/api/people/3')
      log(people3)
    }
    
    main()
    
    正直なところ、私は問題が好きですsleep しかし、私は私がちょうどデモしたそれらのコードのどちらかの構文に全く恋をしていません.これらの2つの例の間で、私は実際にasync/await 構文が悪い.await すべての場所に散らばっていると簡単にミスを犯すのは簡単です.

    非同期関数合成


    機能の構成は強力であり、おそらく完全に理解するために多くの記事を読んでください.だけでなく、どのように、しかし、理由.起動したいならば、ここから始めましょう.Functional JavaScript: Function Composition For Every Day Use .
    私は意図的にこの記事の機能構成を説明していません.私は、私があなたに示している構文がとても機能的な構成を理解する必要がないように単純であると信じています.
    import axios from 'axios'
    import pipe from 'mojiscript/core/pipe'
    import sleep from 'mojiscript/threading/sleep'
    
    const fetchJson = url => axios.get(url).then(response => response.data)
    const log = msg => (console.log(msg), msg)
    
    const main = pipe ([
      () => fetchJson('https://swapi.co/api/people/1'),
      log,
      sleep(1000),
      () => fetchJson('https://swapi.co/api/people/2'),
      log,
      sleep(1000),
      () => fetchJson('https://swapi.co/api/people/3'),
      log
    ])
    
    main()
    
    ダム.それはいくつかの良い探してコードです!
    しかし、我々はすでに機能合成について話しているので、それは抽出するのが簡単ですfetchJson , log , sleep 自分自身にpipe そして、コードをもう少しドライにしてください.
    import axios from 'axios'
    import pipe from 'mojiscript/core/pipe'
    import sleep from 'mojiscript/threading/sleep'
    
    const fetchJson = url => axios.get(url).then(response => response.data)
    const log = msg => (console.log(msg), msg)
    
    const fetchLogWait = pipe ([
      id => fetchJson (`https://swapi.co/api/people/${id}`),
      log,
      sleep(1000)
    ])
    
    const main = pipe ([
      () => fetchLogWait (1),
      () => fetchLogWait (2),
      () => fetchLogWait (3)
    ])
    
    main()
    

    非同期マップ


    MojiScriptも非同期にマップするユニークな機能を持っています.(近い将来、この記事全体を期待してください).
    async mapはこれらの例を書くことを決めた理由ですMojiScript 's pipe の代わりにRamda 's pipeP . この点まで、例はまた、RamdaのものpipeP . この点から、例はmojiscript排他的です.
    若干のコードを見ましょう!非同期にどれくらい簡単かmap Ajax呼び出し
    const main = pipe ([
      ({ start, end }) => range (start) (end + 1),
      map (fetchLogWait),
    ])
    
    main ({ start: 1, end: 3 })
    
    かなりすごく簡単!

    1つのラン可能なコードブロックにまとめます.
    import axios from 'axios'
    import log from 'mojiscript/console/log'
    import pipe from 'mojiscript/core/pipe'
    import map from 'mojiscript/list/map'
    import range from 'mojiscript/list/range'
    import sleep from 'mojiscript/threading/sleep'
    
    const fetchJson = pipe ([
      axios.get,
      response => response.data
    ]) 
    
    const fetchLogWait = pipe ([
      id => fetchJson (`https://swapi.co/api/people/${id}`),
      log,
      sleep (1000)
    ])
    
    const main = pipe ([
      ({ start, end }) => range (start) (end + 1),
      map(fetchLogWait),
    ])
    
    main ({ start: 1, end: 3 })
    
    現在、このコードは、それが得るように乾いています!

    ループ内のsettimeout


    今、あなたはまだこの問題を見ていない場合は、JavaScriptのインタビューの多くの間に与えられます.コードは予想通りに動作しません.出力は何ですか.
    for (var i = 1; i < 6; i++) {
      setTimeout(() => console.log(i), 1000)
    }
    
    あなたがそれを推測しなかったならば6 'sは一度に、あなたは間違っているでしょう.
    同じプログラムpipe とモジスクリットmap . この1つを除いて予想されるように、各出力の前に1秒の一時停止で5を介して番号1を印刷します.
    const sleepThenLog = pipe ([
      sleep (1000),
      log
    ])
    
    const main = pipe ([
      range (1) (6),
      map (sleepThenLog)
    ])
    
    もっとプレイしたいですか?

    グーグルについて

  • Callback Hell
  • Comma Operator
  • Function Composition
  • Ramda
  • MojiScript
  • 概要


    Promise Style関数にスリープを変換する方法は、asyncコードがどのように動くかに関する追加オプションを提供します.
    ラムダpipeP またはMojiscriptのpipe 時々よりきれいであることができますPromises or async/await .
    非同期マップは強力です.
    つの警告は、以下の指摘は、この実装はキャンセルを許可していません.だから必要に応じてclearTimeout , この関数を変更する必要があります.
    私の記事は非常に機能的なJavaScript重いです、あなたがより多くを必要とするならば、ここで、または、さえずりの上で私に続いてください!
    記事を読む
    How I rediscovered my love for JavaScript after throwing 90% of it in the trash