     
     // MARK: - Functions
     // Make preview
-    open func preview(_ text: String!, onSuccess: @escaping (Response) -> Void, onError: @escaping (PreviewError) -> Void) {
+    @discardableResult open func preview(_ text: String!, onSuccess: @escaping (Response) -> Void, onError: @escaping (PreviewError) -> Void) -> () -> Void {
+        
+        let cancellable = Cancellable()
+        
         let successResponseQueue = { (response: Response) in
+            if !cancellable.isCancelled {
             self.responseQueue.async {
-                onSuccess(response)
+                if !cancellable.isCancelled {
+                    onSuccess(response)
+                }
+            }
             }
         }
         
         let errorResponseQueue = { (error: PreviewError) in
+            if !cancellable.isCancelled {
             self.responseQueue.async {
+                if !cancellable.isCancelled {
                 onError(error)
+                }
+            }
             }
         }
         
         workQueue.async {
+            if cancellable.isCancelled {return}
+            
             if let url = self.extractURL(text: text) {
                 if let result = self.cache.slp_getCachedResponse(url: url.absoluteString) {
                     successResponseQueue(result)
                 } else {
-                    self.unshortenURL(url, completion: { unshortened in
+                    self.unshortenURL(url, cancellable: cancellable, completion: { unshortened in
                         if let result = self.cache.slp_getCachedResponse(url: unshortened.absoluteString) {
                             successResponseQueue(result)
                         } else {
                             
                             let canonicalUrl = self.extractCanonicalURL(unshortened)
                             
-                            self.extractInfo(unshortened, canonicalUrl: canonicalUrl, completion: { result in
+                            self.extractInfo(unshortened, cancellable: cancellable, canonicalUrl: canonicalUrl, completion: { result in
                                 
                                 var result = result
                                 

            do {
                let data = try Data(contentsOf: sourceUrl!)
                if let source = String(data: data, encoding: .utf8) {
                    self.parseHtmlString(source, canonicalUrl: canonicalUrl, completion: completion)
                } else {
                    self.tryAnotherEnconding(sourceUrl!, canonicalUrl: canonicalUrl, data: data, encodingArray: String.availableStringEncodings, completion: completion, onError: onError)
                }
            } catch {
                onError(.cannotBeOpened(sourceUrl!.absoluteString))
            }
        }
    }

    // MARK: - Vars
    static let titleMinimumRelevant: Int = 15
    static let decriptionMinimumRelevant: Int = 100
    
    fileprivate let session: URLSession
    fileprivate let workQueue: DispatchQueue
    fileprivate let responseQueue: DispatchQueue
    fileprivate let cache: Cache
    
    public static let defaultWorkQueue = DispatchQueue.global()
    
    // MARK: - Constructor
    public init(session: URLSession = URLSession.shared, workQueue: DispatchQueue = SwiftLinkPreview.defaultWorkQueue, responseQueue: DispatchQueue = DispatchQueue.main, cache: Cache = DisabledCache.instance) {
