public function promise()
    {
        if ($this->promise) {
            return $this->promise;
        }

        return $this->promise = Promise\coroutine(function () {
            // Initiate the upload.
            if ($this->state->isCompleted()) {
                throw new \LogicException('This multipart upload has already '
                    . 'been completed or aborted.'
                );
            } elseif (!$this->state->isInitiated()) {
                $result = (yield $this->execCommand('initiate', $this->getInitiateParams()));
                $this->state->setUploadId(
                    $this->info['id']['upload_id'],
                    $result[$this->info['id']['upload_id']]
                );
                $this->state->setStatus(UploadState::INITIATED);
            }

            // Create a command pool from a generator that yields UploadPart
            // commands for each upload part.
            $resultHandler = $this->getResultHandler($errors);
            $commands = new CommandPool(
                $this->client,
                $this->getUploadCommands($resultHandler),
                [
                    'concurrency' => $this->config['concurrency'],
                    'before'      => $this->config['before_upload'],
                ]
            );

            // Execute the pool of commands concurrently, and process errors.
            yield $commands->promise();
            if ($errors) {
                throw new MultipartUploadException($this->state, $errors);
            }

            // Complete the multipart upload.
            yield $this->execCommand('complete', $this->getCompleteParams());
            $this->state->setStatus(UploadState::COMPLETED);
        })->otherwise(function (\Exception $e) {
            // Throw errors from the operations as a specific Multipart error.
            if ($e instanceof AwsException) {
                $e = new MultipartUploadException($this->state, $e);
            }
            throw $e;
        });
    }