mirror of https://github.com/vapor/docs.git
1967 lines
59 KiB
HTML
1967 lines
59 KiB
HTML
|
|
|
|
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="en" class="no-js">
|
|
<head>
|
|
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
|
|
|
|
|
|
|
|
<meta name="lang:clipboard.copy" content="Copy to clipboard">
|
|
|
|
<meta name="lang:clipboard.copied" content="Copied to clipboard">
|
|
|
|
<meta name="lang:search.language" content="en">
|
|
|
|
<meta name="lang:search.pipeline.stopwords" content="True">
|
|
|
|
<meta name="lang:search.pipeline.trimmer" content="True">
|
|
|
|
<meta name="lang:search.result.none" content="No matching documents">
|
|
|
|
<meta name="lang:search.result.one" content="1 matching document">
|
|
|
|
<meta name="lang:search.result.other" content="# matching documents">
|
|
|
|
<meta name="lang:search.tokenizer" content="[\s\-]+">
|
|
|
|
<link rel="shortcut icon" href="../../assets/images/favicon.png">
|
|
<meta name="generator" content="mkdocs-0.17.3, mkdocs-material-2.7.0">
|
|
|
|
|
|
|
|
<title>Futures - Vapor Docs</title>
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../../assets/stylesheets/application.78aab2dc.css">
|
|
|
|
<link rel="stylesheet" href="../../assets/stylesheets/application-palette.6079476c.css">
|
|
|
|
|
|
|
|
<script src="../../assets/javascripts/modernizr.1aa3b519.js"></script>
|
|
|
|
|
|
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
|
|
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700|Roboto+Mono">
|
|
<style>body,input{font-family:"Roboto","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
|
|
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
|
|
|
|
|
|
|
</head>
|
|
|
|
|
|
|
|
<body dir="ltr" data-md-color-primary="blue" data-md-color-accent="purple">
|
|
|
|
<svg class="md-svg">
|
|
<defs>
|
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
|
|
viewBox="0 0 416 448" id="github">
|
|
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
|
|
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
|
|
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
|
|
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
|
|
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
|
|
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
|
|
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
|
|
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
|
|
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
|
|
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
|
|
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
|
|
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
|
|
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
|
|
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
|
|
99.5z" />
|
|
</svg>
|
|
|
|
</defs>
|
|
</svg>
|
|
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer">
|
|
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="search">
|
|
<label class="md-overlay" data-md-component="overlay" for="drawer"></label>
|
|
|
|
<a href="#futures" tabindex="1" class="md-skip">
|
|
Skip to content
|
|
</a>
|
|
|
|
|
|
<header class="md-header" data-md-component="header">
|
|
<nav class="md-header-nav md-grid">
|
|
<div class="md-flex">
|
|
<div class="md-flex__cell md-flex__cell--shrink">
|
|
<a href="../.." title="Vapor Docs" class="md-header-nav__button md-logo">
|
|
|
|
<img src="../../images/droplet-white.svg" width="24" height="24">
|
|
|
|
</a>
|
|
</div>
|
|
<div class="md-flex__cell md-flex__cell--shrink">
|
|
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
|
|
</div>
|
|
<div class="md-flex__cell md-flex__cell--stretch">
|
|
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
|
|
|
|
|
|
<span class="md-header-nav__topic">
|
|
Vapor Docs
|
|
</span>
|
|
<span class="md-header-nav__topic">
|
|
Futures
|
|
</span>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
<div class="md-flex__cell md-flex__cell--shrink">
|
|
|
|
|
|
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
|
|
|
|
<div class="md-search" data-md-component="search" role="dialog">
|
|
<label class="md-search__overlay" for="search"></label>
|
|
<div class="md-search__inner" role="search">
|
|
<form class="md-search__form" name="search">
|
|
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
|
|
<label class="md-icon md-search__icon" for="search"></label>
|
|
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
|
|

|
|
</button>
|
|
</form>
|
|
<div class="md-search__output">
|
|
<div class="md-search__scrollwrap" data-md-scrollfix>
|
|
<div class="md-search-result" data-md-component="result">
|
|
<div class="md-search-result__meta">
|
|
Type to start searching
|
|
</div>
|
|
<ol class="md-search-result__list"></ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
<div class="md-flex__cell md-flex__cell--shrink">
|
|
<div class="md-header-nav__source">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<a href="http://github.com/vapor/vapor/" title="Go to repository" class="md-source" data-md-source="github">
|
|
|
|
<div class="md-source__icon">
|
|
<svg viewBox="0 0 24 24" width="24" height="24">
|
|
<use xlink:href="#github" width="24" height="24"></use>
|
|
</svg>
|
|
</div>
|
|
|
|
<div class="md-source__repository">
|
|
GitHub
|
|
</div>
|
|
</a>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<div class="md-container">
|
|
|
|
|
|
|
|
|
|
<main class="md-main">
|
|
<div class="md-main__inner md-grid" data-md-component="container">
|
|
|
|
|
|
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
|
|
<div class="md-sidebar__scrollwrap">
|
|
<div class="md-sidebar__inner">
|
|
<nav class="md-nav md-nav--primary" data-md-level="0">
|
|
<label class="md-nav__title md-nav__title--site" for="drawer">
|
|
<span class="md-nav__button md-logo">
|
|
|
|
<img src="../../images/droplet-white.svg" width="48" height="48">
|
|
|
|
</span>
|
|
Vapor Docs
|
|
</label>
|
|
|
|
<div class="md-nav__source">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<a href="http://github.com/vapor/vapor/" title="Go to repository" class="md-source" data-md-source="github">
|
|
|
|
<div class="md-source__icon">
|
|
<svg viewBox="0 0 24 24" width="24" height="24">
|
|
<use xlink:href="#github" width="24" height="24"></use>
|
|
</svg>
|
|
</div>
|
|
|
|
<div class="md-source__repository">
|
|
GitHub
|
|
</div>
|
|
</a>
|
|
|
|
</div>
|
|
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../.." title="Overview" class="md-nav__link">
|
|
Overview
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-2" type="checkbox" id="nav-2">
|
|
|
|
<label class="md-nav__link" for="nav-2">
|
|
Install
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-2">
|
|
Install
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../install/macos/" title="macOS" class="md-nav__link">
|
|
macOS
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../install/ubuntu/" title="Ubuntu" class="md-nav__link">
|
|
Ubuntu
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-3" type="checkbox" id="nav-3" checked>
|
|
|
|
<label class="md-nav__link" for="nav-3">
|
|
Getting started
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-3">
|
|
Getting started
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../hello-world/" title="Hello, world" class="md-nav__link">
|
|
Hello, world
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../toolbox/" title="Toolbox" class="md-nav__link">
|
|
Toolbox
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../spm/" title="SPM" class="md-nav__link">
|
|
SPM
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../xcode/" title="Xcode" class="md-nav__link">
|
|
Xcode
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../structure/" title="Folder Structure" class="md-nav__link">
|
|
Folder Structure
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../application/" title="Application" class="md-nav__link">
|
|
Application
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../controllers/" title="Controllers" class="md-nav__link">
|
|
Controllers
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../routing/" title="Routing" class="md-nav__link">
|
|
Routing
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../content/" title="Content" class="md-nav__link">
|
|
Content
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--active">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__link md-nav__link--active" for="toc">
|
|
Futures
|
|
</label>
|
|
|
|
<a href="./" title="Futures" class="md-nav__link md-nav__link--active">
|
|
Futures
|
|
</a>
|
|
|
|
|
|
<nav class="md-nav md-nav--secondary">
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__title" for="toc">Table of contents</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#transforming" title="Transforming" class="md-nav__link">
|
|
Transforming
|
|
</a>
|
|
|
|
<nav class="md-nav">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#map" title="Map" class="md-nav__link">
|
|
Map
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#flat-map" title="Flat Map" class="md-nav__link">
|
|
Flat Map
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#transform" title="Transform" class="md-nav__link">
|
|
Transform
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#chaining" title="Chaining" class="md-nav__link">
|
|
Chaining
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#future" title="Future" class="md-nav__link">
|
|
Future
|
|
</a>
|
|
|
|
<nav class="md-nav">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#do-catch" title="Do / Catch" class="md-nav__link">
|
|
Do / Catch
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#always" title="Always" class="md-nav__link">
|
|
Always
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#wait" title="Wait" class="md-nav__link">
|
|
Wait
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#promise" title="Promise" class="md-nav__link">
|
|
Promise
|
|
</a>
|
|
|
|
<nav class="md-nav">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#thread-safety" title="Thread Safety" class="md-nav__link">
|
|
Thread Safety
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#event-loop" title="Event Loop" class="md-nav__link">
|
|
Event Loop
|
|
</a>
|
|
|
|
<nav class="md-nav">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#worker" title="Worker" class="md-nav__link">
|
|
Worker
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#blocking" title="Blocking" class="md-nav__link">
|
|
Blocking
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../services/" title="Services" class="md-nav__link">
|
|
Services
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../cloud/" title="Deployment" class="md-nav__link">
|
|
Deployment
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-4" type="checkbox" id="nav-4">
|
|
|
|
<label class="md-nav__link" for="nav-4">
|
|
Routing
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-4">
|
|
Routing
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../routing/getting-started/" title="Getting Started" class="md-nav__link">
|
|
Getting Started
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../routing/parameters/" title="Parameters" class="md-nav__link">
|
|
Parameters
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../routing/route/" title="Route" class="md-nav__link">
|
|
Route
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../routing/router/" title="Router" class="md-nav__link">
|
|
Router
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-5" type="checkbox" id="nav-5">
|
|
|
|
<label class="md-nav__link" for="nav-5">
|
|
Fluent
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-5">
|
|
Fluent
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../fluent/getting-started/" title="Getting Started" class="md-nav__link">
|
|
Getting Started
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../fluent/models/" title="Models" class="md-nav__link">
|
|
Models
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../fluent/migrations/" title="Migrations" class="md-nav__link">
|
|
Migrations
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../fluent/querying/" title="Querying" class="md-nav__link">
|
|
Querying
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../fluent/query-builder/" title="Query Builder" class="md-nav__link">
|
|
Query Builder
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../fluent/schema-builder/" title="Schema Builder" class="md-nav__link">
|
|
Schema Builder
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../fluent/relations/" title="Relations" class="md-nav__link">
|
|
Relations
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../fluent/pivot/" title="Pivot" class="md-nav__link">
|
|
Pivot
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../fluent/transaction/" title="Transaction" class="md-nav__link">
|
|
Transaction
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../fluent/database/" title="Database" class="md-nav__link">
|
|
Database
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6">
|
|
|
|
<label class="md-nav__link" for="nav-6">
|
|
PostgreSQL
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-6">
|
|
PostgreSQL
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../postgresql/getting-started/" title="Getting Started" class="md-nav__link">
|
|
Getting Started
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../postgresql/fluent/" title="Fluent PostgreSQL" class="md-nav__link">
|
|
Fluent PostgreSQL
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../postgresql/core/" title="PostgreSQL Core" class="md-nav__link">
|
|
PostgreSQL Core
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-7" type="checkbox" id="nav-7">
|
|
|
|
<label class="md-nav__link" for="nav-7">
|
|
MySQL
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-7">
|
|
MySQL
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../mysql/getting-started/" title="Getting Started" class="md-nav__link">
|
|
Getting Started
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../mysql/fluent/" title="Fluent MySQL" class="md-nav__link">
|
|
Fluent MySQL
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../mysql/core/" title="MySQL Core" class="md-nav__link">
|
|
MySQL Core
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-8" type="checkbox" id="nav-8">
|
|
|
|
<label class="md-nav__link" for="nav-8">
|
|
SQLite
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-8">
|
|
SQLite
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../sqlite/getting-started/" title="Getting Started" class="md-nav__link">
|
|
Getting Started
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../sqlite/fluent/" title="Fluent SQLite" class="md-nav__link">
|
|
Fluent SQLite
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../sqlite/core/" title="SQLite Core" class="md-nav__link">
|
|
SQLite Core
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-9" type="checkbox" id="nav-9">
|
|
|
|
<label class="md-nav__link" for="nav-9">
|
|
Leaf
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-9">
|
|
Leaf
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../leaf/getting-started/" title="Getting Started" class="md-nav__link">
|
|
Getting Started
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../leaf/basics/" title="Basics" class="md-nav__link">
|
|
Basics
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../leaf/custom-tags/" title="Custom tags" class="md-nav__link">
|
|
Custom tags
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-10" type="checkbox" id="nav-10">
|
|
|
|
<label class="md-nav__link" for="nav-10">
|
|
Redis
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-10">
|
|
Redis
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../redis/getting-started/" title="Getting Started" class="md-nav__link">
|
|
Getting Started
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../redis/basics/" title="Basics" class="md-nav__link">
|
|
Basics
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../redis/custom-commands/" title="Custom commands" class="md-nav__link">
|
|
Custom commands
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../redis/pub-sub/" title="Publish and Subscribe" class="md-nav__link">
|
|
Publish and Subscribe
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../redis/pipeline/" title="Pipeline" class="md-nav__link">
|
|
Pipeline
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-11" type="checkbox" id="nav-11">
|
|
|
|
<label class="md-nav__link" for="nav-11">
|
|
WebSocket
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-11">
|
|
WebSocket
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../websocket/websocket/" title="Getting Started" class="md-nav__link">
|
|
Getting Started
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-12" type="checkbox" id="nav-12">
|
|
|
|
<label class="md-nav__link" for="nav-12">
|
|
Crypto
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-12">
|
|
Crypto
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../crypto/getting-started/" title="Getting Started" class="md-nav__link">
|
|
Getting Started
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../crypto/base64/" title="Base64" class="md-nav__link">
|
|
Base64
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../crypto/hash/" title="Hashes" class="md-nav__link">
|
|
Hashes
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../crypto/mac/" title="Message authentication" class="md-nav__link">
|
|
Message authentication
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../crypto/passwords/" title="Password hashing" class="md-nav__link">
|
|
Password hashing
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../crypto/random/" title="Random" class="md-nav__link">
|
|
Random
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-13" type="checkbox" id="nav-13">
|
|
|
|
<label class="md-nav__link" for="nav-13">
|
|
Testing
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-13">
|
|
Testing
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../testing/getting-started/" title="Getting Started" class="md-nav__link">
|
|
Getting Started
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-14" type="checkbox" id="nav-14">
|
|
|
|
<label class="md-nav__link" for="nav-14">
|
|
Deploy
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-14">
|
|
Deploy
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../deploy/getting-started/" title="Getting Started" class="md-nav__link">
|
|
Getting Started
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-15" type="checkbox" id="nav-15">
|
|
|
|
<label class="md-nav__link" for="nav-15">
|
|
Version (3.0-rc)
|
|
</label>
|
|
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
|
|
<label class="md-nav__title" for="nav-15">
|
|
Version (3.0-rc)
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../version/1_5/" title="1.5" class="md-nav__link">
|
|
1.5
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../version/2_0/" title="2.0" class="md-nav__link">
|
|
2.0
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../version/3_0/" title="3.0-rc" class="md-nav__link">
|
|
3.0-rc
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../version/support/" title="Support" class="md-nav__link">
|
|
Support
|
|
</a>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
|
|
<div class="md-sidebar__scrollwrap">
|
|
<div class="md-sidebar__inner">
|
|
|
|
<nav class="md-nav md-nav--secondary">
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__title" for="toc">Table of contents</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#transforming" title="Transforming" class="md-nav__link">
|
|
Transforming
|
|
</a>
|
|
|
|
<nav class="md-nav">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#map" title="Map" class="md-nav__link">
|
|
Map
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#flat-map" title="Flat Map" class="md-nav__link">
|
|
Flat Map
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#transform" title="Transform" class="md-nav__link">
|
|
Transform
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#chaining" title="Chaining" class="md-nav__link">
|
|
Chaining
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#future" title="Future" class="md-nav__link">
|
|
Future
|
|
</a>
|
|
|
|
<nav class="md-nav">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#do-catch" title="Do / Catch" class="md-nav__link">
|
|
Do / Catch
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#always" title="Always" class="md-nav__link">
|
|
Always
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#wait" title="Wait" class="md-nav__link">
|
|
Wait
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#promise" title="Promise" class="md-nav__link">
|
|
Promise
|
|
</a>
|
|
|
|
<nav class="md-nav">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#thread-safety" title="Thread Safety" class="md-nav__link">
|
|
Thread Safety
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#event-loop" title="Event Loop" class="md-nav__link">
|
|
Event Loop
|
|
</a>
|
|
|
|
<nav class="md-nav">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#worker" title="Worker" class="md-nav__link">
|
|
Worker
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#blocking" title="Blocking" class="md-nav__link">
|
|
Blocking
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="md-content">
|
|
<article class="md-content__inner md-typeset">
|
|
|
|
|
|
<a href="https://github.com/vapor/documentation/edit/master/3.0/docs/getting-started/futures.md" title="Edit this page" class="md-icon md-content__icon"></a>
|
|
|
|
|
|
<h1 id="futures">Futures<a class="headerlink" href="#futures" title="Permanent link">¶</a></h1>
|
|
<p>You may have noticed some APIs in Vapor expect or return a generic <code>Future</code> type. If this is your first time hearing about futures, they might seem a little confusing at first. But don't worry, Vapor makes them easy to use.</p>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Info</p>
|
|
<p>The promises, futures, and event loops that Vapor uses all come from the <a href="https://github.com/apple/swift-nio">Swift NIO</a> library. This document covers the basics as well as some type-aliases and extensions that Vapor adds to make things more convenient.</p>
|
|
</div>
|
|
<p>Promises and futures are related, but distinct types. Promises are used to <em>create</em> futures. Most of the time, you will be working with futures returned by Vapor's APIs and you will not need to worry about creating promises.</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>type</th>
|
|
<th>description</th>
|
|
<th>mutability</th>
|
|
<th>methods</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>Future</code></td>
|
|
<td>Reference to an object that may not be available yet.</td>
|
|
<td>read-only</td>
|
|
<td><code>.map(to:_:)</code> <code>.flatMap(to:_:)</code> <code>do(_:)</code> <code>catch(_:)</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>Promise</code></td>
|
|
<td>A promise to provide some object asynchronously.</td>
|
|
<td>read/write</td>
|
|
<td><code>succeed(_:)</code> <code>fail(_:)</code></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>Futures are an alternative to callback-based asynchronous APIs. Futures can be chained and transformed in ways that simple closures cannot, making them quite powerful.</p>
|
|
<h2 id="transforming">Transforming<a class="headerlink" href="#transforming" title="Permanent link">¶</a></h2>
|
|
<p>Just like optionals in Swift, futures can be mapped and flat-mapped. These are the most common operations you will perform on futures.</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>method</th>
|
|
<th>signature</th>
|
|
<th>description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>map</code></td>
|
|
<td><code>to: U.Type, _: (T) -> U</code></td>
|
|
<td>Maps a future value to a different value.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>flatMap</code></td>
|
|
<td><code>to: U.Type, _: (T) -> Future<U></code></td>
|
|
<td>Maps a future value to different <em>future</em> value.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>transform</code></td>
|
|
<td><code>to: U</code></td>
|
|
<td>Maps a future to an already available value.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>If you look at the method signatures for <code>map</code> and <code>flatMap</code> on <code>Optional<T></code> and <code>Array<T></code>, you will see the are very similar to the methods available on <code>Future<T></code>.</p>
|
|
<h3 id="map">Map<a class="headerlink" href="#map" title="Permanent link">¶</a></h3>
|
|
<p>The <code>.map(to:_:)</code> method allows you to transform the future's value to another value. Because the future's value may not be available yet (it may be the result of an asynchronous task) we must provide a closure to accept the value.</p>
|
|
<div class="codehilite"><pre><span></span><span class="c1">/// Assume we get a future string back from some API</span>
|
|
<span class="kd">let</span> <span class="nv">futureString</span><span class="p">:</span> <span class="n">Future</span><span class="p"><</span><span class="nb">String</span><span class="p">></span> <span class="p">=</span> <span class="p">...</span>
|
|
|
|
<span class="c1">/// Map the future string to an integer</span>
|
|
<span class="kd">let</span> <span class="nv">futureInt</span> <span class="p">=</span> <span class="n">futureString</span><span class="p">.</span><span class="bp">map</span><span class="p">(</span><span class="n">to</span><span class="p">:</span> <span class="nb">Int</span><span class="p">.</span><span class="kc">self</span><span class="p">)</span> <span class="p">{</span> <span class="n">string</span> <span class="k">in</span>
|
|
<span class="bp">print</span><span class="p">(</span><span class="n">string</span><span class="p">)</span> <span class="c1">// The actual String</span>
|
|
<span class="k">return</span> <span class="nb">Int</span><span class="p">(</span><span class="n">string</span><span class="p">)</span> <span class="p">??</span> <span class="mi">0</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="c1">/// We now have a future integer</span>
|
|
<span class="bp">print</span><span class="p">(</span><span class="n">futureInt</span><span class="p">)</span> <span class="c1">// Future<Int></span>
|
|
</pre></div>
|
|
|
|
|
|
<h3 id="flat-map">Flat Map<a class="headerlink" href="#flat-map" title="Permanent link">¶</a></h3>
|
|
<p>The <code>.flatMap(to:_:)</code> method allows you to transform the future's value to another future value. It gets the name "flat" map because it is what allows you to avoid creating nested futures (i.e., <code>Future<Future<T>></code>). In other words, it helps you keep your generic futures flat.</p>
|
|
<div class="codehilite"><pre><span></span><span class="c1">/// Assume we get a future string back from some API</span>
|
|
<span class="kd">let</span> <span class="nv">futureString</span><span class="p">:</span> <span class="n">Future</span><span class="p"><</span><span class="nb">String</span><span class="p">></span> <span class="p">=</span> <span class="p">...</span>
|
|
|
|
<span class="c1">/// Assume we have created an HTTP client</span>
|
|
<span class="kd">let</span> <span class="nv">client</span><span class="p">:</span> <span class="n">Client</span> <span class="p">=</span> <span class="p">...</span>
|
|
|
|
<span class="c1">/// Flat-map the future string to a future response</span>
|
|
<span class="kd">let</span> <span class="nv">futureResponse</span> <span class="p">=</span> <span class="n">futureString</span><span class="p">.</span><span class="n">flatMap</span><span class="p">(</span><span class="n">to</span><span class="p">:</span> <span class="n">Response</span><span class="p">.</span><span class="kc">self</span><span class="p">)</span> <span class="p">{</span> <span class="n">string</span> <span class="k">in</span>
|
|
<span class="k">return</span> <span class="n">client</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="n">string</span><span class="p">)</span> <span class="c1">// Future<Response></span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="c1">/// We now have a future response</span>
|
|
<span class="bp">print</span><span class="p">(</span><span class="n">futureResponse</span><span class="p">)</span> <span class="c1">// Future<Response></span>
|
|
</pre></div>
|
|
|
|
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Info</p>
|
|
<p>If we instead used <code>.map(to:_:)</code> in the above example, we would have ended up with a <code>Future<Future<Response>></code>. Yikes!</p>
|
|
</div>
|
|
<h3 id="transform">Transform<a class="headerlink" href="#transform" title="Permanent link">¶</a></h3>
|
|
<p>The <code>.transform(_:)</code> method allows you to modify a future's value, ignoring the existing value. This is especially useful for transforming the results of <code>Future<Void></code> where the actual value of the future is not important.</p>
|
|
<div class="admonition tip">
|
|
<p class="admonition-title">Tip</p>
|
|
<p><code>Future<Void></code>, sometimes called a signal, is a future whose sole purpose is to notify you of completion or failure of some async operation.</p>
|
|
</div>
|
|
<div class="codehilite"><pre><span></span><span class="c1">/// Assume we get a void future back from some API</span>
|
|
<span class="kd">let</span> <span class="nv">userDidSave</span><span class="p">:</span> <span class="n">Future</span><span class="p"><</span><span class="nb">Void</span><span class="p">></span> <span class="p">=</span> <span class="p">...</span>
|
|
|
|
<span class="c1">/// Transform the void future to an HTTP status</span>
|
|
<span class="kd">let</span> <span class="nv">futureStatus</span> <span class="p">=</span> <span class="n">userDidSave</span><span class="p">.</span><span class="n">transform</span><span class="p">(</span><span class="n">to</span><span class="p">:</span> <span class="n">HTTPStatus</span><span class="p">.</span><span class="n">ok</span><span class="p">)</span>
|
|
<span class="bp">print</span><span class="p">(</span><span class="n">futureStatus</span><span class="p">)</span> <span class="c1">// Future<HTTPStatus></span>
|
|
</pre></div>
|
|
|
|
|
|
<p>Even though we have supplied an already-available value to <code>transform</code>, this is still a <em>transformation</em>. The future will not complete until all previous futures have completed (or failed).</p>
|
|
<h3 id="chaining">Chaining<a class="headerlink" href="#chaining" title="Permanent link">¶</a></h3>
|
|
<p>The great part about transformations on futures is that they can be chained. This allows you to express many conversions and subtasks easily.</p>
|
|
<p>Let's modify the examples from above to see how we can take advantage of chaining.</p>
|
|
<div class="codehilite"><pre><span></span><span class="c1">/// Assume we get a future string back from some API</span>
|
|
<span class="kd">let</span> <span class="nv">futureString</span><span class="p">:</span> <span class="n">Future</span><span class="p"><</span><span class="nb">String</span><span class="p">></span> <span class="p">=</span> <span class="p">...</span>
|
|
|
|
<span class="c1">/// Assume we have created an HTTP client</span>
|
|
<span class="kd">let</span> <span class="nv">client</span><span class="p">:</span> <span class="n">Client</span> <span class="p">=</span> <span class="p">...</span>
|
|
|
|
<span class="c1">/// Transform the string to a url, then to a response</span>
|
|
<span class="kd">let</span> <span class="nv">futureResponse</span> <span class="p">=</span> <span class="n">futureString</span><span class="p">.</span><span class="bp">map</span><span class="p">(</span><span class="n">to</span><span class="p">:</span> <span class="n">URL</span><span class="p">.</span><span class="kc">self</span><span class="p">)</span> <span class="p">{</span> <span class="n">string</span> <span class="k">in</span>
|
|
<span class="k">guard</span> <span class="kd">let</span> <span class="nv">url</span> <span class="p">=</span> <span class="n">URL</span><span class="p">(</span><span class="n">string</span><span class="p">:</span> <span class="n">string</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span>
|
|
<span class="k">throw</span> <span class="n">Abort</span><span class="p">(.</span><span class="n">badRequest</span><span class="p">,</span> <span class="n">reason</span><span class="p">:</span> <span class="s">"Invalid URL string: </span><span class="si">\(</span><span class="n">string</span><span class="si">)</span><span class="s">"</span><span class="p">)</span>
|
|
<span class="p">}</span>
|
|
<span class="k">return</span> <span class="n">url</span>
|
|
<span class="p">}.</span><span class="n">flatMap</span><span class="p">(</span><span class="n">to</span><span class="p">:</span> <span class="n">Response</span><span class="p">.</span><span class="kc">self</span><span class="p">)</span> <span class="p">{</span> <span class="n">url</span> <span class="k">in</span>
|
|
<span class="k">return</span> <span class="n">client</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="bp">print</span><span class="p">(</span><span class="n">futureResponse</span><span class="p">)</span> <span class="c1">// Future<Response></span>
|
|
</pre></div>
|
|
|
|
|
|
<p>After the initial call to map, there is a temporary <code>Future<URL></code> created. This future is then immediately flat-mapped to a <code>Future<Response></code></p>
|
|
<div class="admonition tip">
|
|
<p class="admonition-title">Tip</p>
|
|
<p>You can <code>throw</code> errors inside of map and flat-map closures. This will result in the future failing with the error thrown.</p>
|
|
</div>
|
|
<h2 id="future">Future<a class="headerlink" href="#future" title="Permanent link">¶</a></h2>
|
|
<p>Let's take a look at some other, less commonly used methods on <code>Future<T></code>.</p>
|
|
<h3 id="do-catch">Do / Catch<a class="headerlink" href="#do-catch" title="Permanent link">¶</a></h3>
|
|
<p>Similar to Swift's <code>do</code> / <code>catch</code> syntax, futures have a <code>do</code> and <code>catch</code> method for awaiting the future's result.</p>
|
|
<div class="codehilite"><pre><span></span><span class="c1">/// Assume we get a future string back from some API</span>
|
|
<span class="kd">let</span> <span class="nv">futureString</span><span class="p">:</span> <span class="n">Future</span><span class="p"><</span><span class="nb">String</span><span class="p">></span> <span class="p">=</span> <span class="p">...</span>
|
|
|
|
<span class="n">futureString</span><span class="p">.</span><span class="k">do</span> <span class="p">{</span> <span class="n">string</span> <span class="k">in</span>
|
|
<span class="bp">print</span><span class="p">(</span><span class="n">string</span><span class="p">)</span> <span class="c1">// The actual String</span>
|
|
<span class="p">}.</span><span class="k">catch</span> <span class="p">{</span> <span class="n">error</span> <span class="k">in</span>
|
|
<span class="bp">print</span><span class="p">(</span><span class="n">error</span><span class="p">)</span> <span class="c1">// A Swift Error</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
|
|
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Info</p>
|
|
<p><code>.do</code> and <code>.catch</code> work together. If you forget <code>.catch</code>, the compiler will warn you about an unused result. Don't forget to handle the error case!</p>
|
|
</div>
|
|
<h3 id="always">Always<a class="headerlink" href="#always" title="Permanent link">¶</a></h3>
|
|
<p>You can use <code>always</code> to add a callback that will be executed whether the future succeeds or fails.</p>
|
|
<div class="codehilite"><pre><span></span><span class="c1">/// Assume we get a future string back from some API</span>
|
|
<span class="kd">let</span> <span class="nv">futureString</span><span class="p">:</span> <span class="n">Future</span><span class="p"><</span><span class="nb">String</span><span class="p">></span> <span class="p">=</span> <span class="p">...</span>
|
|
|
|
<span class="n">futureString</span><span class="p">.</span><span class="n">always</span> <span class="p">{</span>
|
|
<span class="bp">print</span><span class="p">(</span><span class="s">"The future is complete!"</span><span class="p">)</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
|
|
|
|
<div class="admonition note">
|
|
<p class="admonition-title">Note</p>
|
|
<p>You can add as many callbacks to a future as you want.</p>
|
|
</div>
|
|
<h3 id="wait">Wait<a class="headerlink" href="#wait" title="Permanent link">¶</a></h3>
|
|
<p>You can use <code>.wait()</code> to synchronously wait for the future to be completed. Since a future may fail, this call is throwing.</p>
|
|
<div class="codehilite"><pre><span></span><span class="c1">/// Assume we get a future string back from some API</span>
|
|
<span class="kd">let</span> <span class="nv">futureString</span><span class="p">:</span> <span class="n">Future</span><span class="p"><</span><span class="nb">String</span><span class="p">></span> <span class="p">=</span> <span class="p">...</span>
|
|
|
|
<span class="c1">/// Block until the string is ready</span>
|
|
<span class="kd">let</span> <span class="nv">string</span> <span class="p">=</span> <span class="k">try</span> <span class="n">futureString</span><span class="p">.</span><span class="n">wait</span><span class="p">()</span>
|
|
<span class="bp">print</span><span class="p">(</span><span class="n">string</span><span class="p">)</span> <span class="c1">/// String</span>
|
|
</pre></div>
|
|
|
|
|
|
<div class="admonition warning">
|
|
<p class="admonition-title">Warning</p>
|
|
<p>Do not use this method in route closures or controllers. Read the section about <a href="#blocking">Blocking</a> for more information.</p>
|
|
</div>
|
|
<h2 id="promise">Promise<a class="headerlink" href="#promise" title="Permanent link">¶</a></h2>
|
|
<p>Most of the time, you will be transforming futures returned by calls to Vapor's APIs. However, at some point you may need to create a promise of your own.</p>
|
|
<p>To create a promise, you will need access to an <code>EventLoop</code>. All containers in Vapor have an <code>eventLoop</code> property that you can use. Most commonly, this will be the current <code>Request</code>.</p>
|
|
<div class="codehilite"><pre><span></span><span class="c1">/// Create a new promise for some string</span>
|
|
<span class="kd">let</span> <span class="nv">promiseString</span> <span class="p">=</span> <span class="n">req</span><span class="p">.</span><span class="n">eventLoop</span><span class="p">.</span><span class="n">newPromise</span><span class="p">(</span><span class="nb">String</span><span class="p">.</span><span class="kc">self</span><span class="p">)</span>
|
|
<span class="bp">print</span><span class="p">(</span><span class="n">promiseString</span><span class="p">)</span> <span class="c1">// Promise<String></span>
|
|
<span class="bp">print</span><span class="p">(</span><span class="n">promiseString</span><span class="p">.</span><span class="n">futureResult</span><span class="p">)</span> <span class="c1">// Future<String></span>
|
|
|
|
<span class="c1">/// Completes the associated future</span>
|
|
<span class="n">promiseString</span><span class="p">.</span><span class="n">succeed</span><span class="p">(</span><span class="n">result</span><span class="p">:</span> <span class="s">"Hello"</span><span class="p">)</span>
|
|
|
|
<span class="c1">/// Fails the associated future</span>
|
|
<span class="n">promiseString</span><span class="p">.</span><span class="n">fail</span><span class="p">(</span><span class="n">error</span><span class="p">:</span> <span class="p">...)</span>
|
|
</pre></div>
|
|
|
|
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Info</p>
|
|
<p>A promise can only be completed once. Any subsequent completions will be ignored.</p>
|
|
</div>
|
|
<h3 id="thread-safety">Thread Safety<a class="headerlink" href="#thread-safety" title="Permanent link">¶</a></h3>
|
|
<p>Promises can be completed (<code>succeed(result:)</code> / <code>fail(error:)</code>) from any thread. This is why promises require an event-loop to be initialized. Promises ensure that the completion action gets returned to its event-loop for execution.</p>
|
|
<h2 id="event-loop">Event Loop<a class="headerlink" href="#event-loop" title="Permanent link">¶</a></h2>
|
|
<p>When your application boots, it will usually create one event loop for each core in the CPU it is running on. Each event loop has exactly one thread. If you are familiar with event loops from Node.js, the one's in Vapor are very similar. The only difference is that Vapor can run multiple event loops in one process since Swift supports multi-threading.</p>
|
|
<p>Each time a client connects to your server, it will be assigned to one of the event loops. From that point on, all communication between the server and that client will happen on that same event loop (and by association, that event loop's thread). </p>
|
|
<p>The event loop is responsible for keeping track of each connected client's state. If there is a request from the client waiting to be read, the event loop trigger a read notification, causing the data to be read. Once the entire request is read, any futures waiting for that request's data will be completed. </p>
|
|
<h3 id="worker">Worker<a class="headerlink" href="#worker" title="Permanent link">¶</a></h3>
|
|
<p>Things that have access to an event loop are called <code>Workers</code>. Every container in Vapor is a worker. </p>
|
|
<p>The most common containers you will interact with in Vapor are:</p>
|
|
<ul>
|
|
<li><code>Application</code></li>
|
|
<li><code>Request</code></li>
|
|
<li><code>Response</code></li>
|
|
</ul>
|
|
<p>You can use the <code>.eventLoop</code> property on these containers to gain access to the event loop.</p>
|
|
<div class="codehilite"><pre><span></span><span class="bp">print</span><span class="p">(</span><span class="n">app</span><span class="p">.</span><span class="n">eventLoop</span><span class="p">)</span> <span class="c1">// EventLoop</span>
|
|
</pre></div>
|
|
|
|
|
|
<p>There are many methods in Vapor that require the current worker to be passed along. It will usually be labeled like <code>on: Worker</code>. If you are in a route closure or a controller, pass the current <code>Request</code> or <code>Response</code>. If you need a worker while booting your app, use the <code>Application</code>.</p>
|
|
<h3 id="blocking">Blocking<a class="headerlink" href="#blocking" title="Permanent link">¶</a></h3>
|
|
<p>An absolutely critical rule is the following:</p>
|
|
<div class="admonition danger">
|
|
<p class="admonition-title">Danger</p>
|
|
<p>Never make blocking calls directly on an event loop.</p>
|
|
</div>
|
|
<p>An example of a blocking call would be something like <code>libc.sleep(_:)</code>.</p>
|
|
<div class="codehilite"><pre><span></span><span class="n">router</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s">"hello"</span><span class="p">)</span> <span class="p">{</span> <span class="n">req</span> <span class="k">in</span>
|
|
<span class="c1">/// Puts the event loop's thread to sleep.</span>
|
|
<span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
|
|
|
|
<span class="c1">/// Returns a simple string once the thread re-awakens.</span>
|
|
<span class="k">return</span> <span class="s">"Hello, world!"</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
|
|
|
|
<p><code>sleep(_:)</code> is a command that blocks the current thread for the number of seconds supplied. If you do blocking work directly on an event loop, the event loop will be unable to respond to any other clients assigned to it for the duration of the blocking work. In other words, if you do <code>sleep(5)</code> on an event loop, all of the other clients connected to that event loop (possibly hundreds or thousands) will be delayed for at least 5 seconds.</p>
|
|
<p>Make sure to run any blocking work in the background. Use promises to notify the event loop when this work is done in a non-blocking way.</p>
|
|
<div class="codehilite"><pre><span></span><span class="n">router</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s">"hello"</span><span class="p">)</span> <span class="p">{</span> <span class="n">req</span> <span class="k">in</span>
|
|
<span class="c1">/// Create a new void promise</span>
|
|
<span class="kd">let</span> <span class="nv">promise</span> <span class="p">=</span> <span class="n">req</span><span class="p">.</span><span class="n">eventLoop</span><span class="p">.</span><span class="n">newPromise</span><span class="p">(</span><span class="nb">Void</span><span class="p">.</span><span class="kc">self</span><span class="p">)</span>
|
|
|
|
<span class="c1">/// Dispatch some work to happen on a background thread</span>
|
|
<span class="n">DispatchQueue</span><span class="p">.</span><span class="n">global</span><span class="p">()</span> <span class="p">{</span>
|
|
<span class="c1">/// Puts the background thread to sleep</span>
|
|
<span class="c1">/// This will not affect any of the event loops</span>
|
|
<span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
|
|
|
|
<span class="c1">/// When the "blocking work" has completed,</span>
|
|
<span class="c1">/// complete the promise and its associated future.</span>
|
|
<span class="n">promise</span><span class="p">.</span><span class="n">succeed</span><span class="p">()</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="c1">/// Wait for the future to be completed, </span>
|
|
<span class="c1">/// then transform the result to a simple String</span>
|
|
<span class="k">return</span> <span class="n">promise</span><span class="p">.</span><span class="n">futureResult</span><span class="p">.</span><span class="n">transform</span><span class="p">(</span><span class="n">to</span><span class="p">:</span> <span class="s">"Hello, world!"</span><span class="p">)</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
|
|
|
|
<p>Not all blocking calls will be as obvious as <code>sleep(_:)</code>. If you are suspicious that a call you are using may be blocking, research the method itself or ask someone. Chances are if the function is doing disk or network IO and uses a synchronous API (no callbacks or futures) it is blocking.</p>
|
|
<div class="admonition info">
|
|
<p class="admonition-title">Info</p>
|
|
<p>If doing blocking work is a central part of your application, you should consider using a <code>BlockingIOThreadPool</code> to control the number of threads you create to do blocking work. This will help you avoid starving your event loops from CPU time while blocking work is being done.</p>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</article>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
|
|
<footer class="md-footer">
|
|
|
|
<div class="md-footer-nav">
|
|
<nav class="md-footer-nav__inner md-grid">
|
|
|
|
<a href="../content/" title="Content" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
|
|
<div class="md-flex__cell md-flex__cell--shrink">
|
|
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
|
|
</div>
|
|
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
|
|
<span class="md-flex__ellipsis">
|
|
<span class="md-footer-nav__direction">
|
|
Previous
|
|
</span>
|
|
Content
|
|
</span>
|
|
</div>
|
|
</a>
|
|
|
|
|
|
<a href="../services/" title="Services" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
|
|
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
|
|
<span class="md-flex__ellipsis">
|
|
<span class="md-footer-nav__direction">
|
|
Next
|
|
</span>
|
|
Services
|
|
</span>
|
|
</div>
|
|
<div class="md-flex__cell md-flex__cell--shrink">
|
|
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
|
|
</div>
|
|
</a>
|
|
|
|
</nav>
|
|
</div>
|
|
|
|
<div class="md-footer-meta md-typeset">
|
|
<div class="md-footer-meta__inner md-grid">
|
|
<div class="md-footer-copyright">
|
|
|
|
<div class="md-footer-copyright__highlight">
|
|
Copyright © 2018 Qutheory, LLC
|
|
</div>
|
|
|
|
powered by
|
|
<a href="http://www.mkdocs.org">MkDocs</a>
|
|
and
|
|
<a href="https://squidfunk.github.io/mkdocs-material/">
|
|
Material for MkDocs</a>
|
|
</div>
|
|
|
|
|
|
<div class="md-footer-social">
|
|
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
|
|
|
<a href="https://twitter.com/@codevapor" class="md-footer-social__link fa fa-twitter"></a>
|
|
|
|
<a href="http://vapor.team/" class="md-footer-social__link fa fa-slack"></a>
|
|
|
|
<a href="https://github.com/vapor" class="md-footer-social__link fa fa-github"></a>
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
</div>
|
|
|
|
<script src="../../assets/javascripts/application.8eb9be28.js"></script>
|
|
|
|
<script>app.initialize({version:"0.17.3",url:{base:"../.."}})</script>
|
|
|
|
|
|
|
|
|
|
<script>!function(e,a,t,n,o,c,i){e.GoogleAnalyticsObject=o,e.ga=e.ga||function(){(e.ga.q=e.ga.q||[]).push(arguments)},e.ga.l=1*new Date,c=a.createElement(t),i=a.getElementsByTagName(t)[0],c.async=1,c.src="https://www.google-analytics.com/analytics.js",i.parentNode.insertBefore(c,i)}(window,document,"script",0,"ga"),ga("create","UA-76177358-4","auto"),ga("set","anonymizeIp",!0),ga("send","pageview");var links=document.getElementsByTagName("a");if(Array.prototype.map.call(links,function(e){e.host!=document.location.host&&e.addEventListener("click",function(){var a=e.getAttribute("data-md-action")||"follow";ga("send","event","outbound",a,e.href)})}),document.forms.search){var query=document.forms.search.query;query.addEventListener("blur",function(){if(this.value){var e=document.location.pathname;ga("send","pageview",e+"?q="+this.value)}})}</script>
|
|
|
|
|
|
</body>
|
|
</html> |