如何仅在第一个完成后才发出后续 API 请求?

Posted

技术标签:

【中文标题】如何仅在第一个完成后才发出后续 API 请求?【英文标题】:How to issue a subsequent API request only after the first was done? 【发布时间】:2017-02-19 08:00:54 【问题描述】:

我需要调用一个 API 来上传照片,这个 API 返回照片的 ID。然后,我需要获取该 ID 并将其用作另一个 API 的参数。

问题是,第二个 API 在第一个 API 有机会完成(并返回 ID)之前被调用。对此有什么办法?

我正在使用 Alamofire 4 和 Swift 3。

我的代码:

 // First API - Upload file
func uploadFile(url: String, image: UIImage, callback: @escaping (JSON) -> ()) 

    let imageData = UIImagePNGRepresentation(image)

    let URL2 = try! URLRequest(url: url, method: .post, headers: header)

    Alamofire.upload(multipartFormData:  (multipartFormData) in

        multipartFormData.append(imageData!, withName: "photo", fileName: "picture.png", mimeType: "image/png")

    , with: URL2, encodingCompletion:  (result) in
        switch result 
        case .success(let upload, _, _):
            upload.responseJSON
                
                    response in

                    switch response.result 
                    case .success(let value):
                        let json = JSON(value)
                        callback(json)
                    case .failure(let error):
                        print(error)
                    
            
        case .failure(let encodingError):
            print(encodingError)
        
    )


 // Second API
 func Post(url: String, parameters: [String:Any], callback: @escaping (JSON) -> ()) 

    Alamofire.request(url, method: .post, parameters: parameters.asParameters(), encoding: ArrayEncoding(), headers: header).responseData  (response) in
        switch response.result 
        case .success(let value):
            callback(json)
        case .failure(let error):
            print(error)
        
    


// Calling the First API
var uploadedImage: [String:String]!
uploadFile(url: baseUrl, image: image, callback:  (json) in
            DispatchQueue.main.async 
                    uploadedImage = ["filename": json["data"]["photo"]["filename"].stringValue, "_id": json["data"]["photo"]["_id"].stringValue]
                
        )

// Calling the Second API
Post(url: baseUrl, parameters: uploadedImage)  (json) in
        DispatchQueue.main.async 
            self.activityIndicator.stopAnimating() 
        

【问题讨论】:

一般来说,在这种情况下避免并发的方法是将调用第二个 API 放在第一个的“成功回调”中(意味着第一个必须在那时完成)。 @Dev-iL 你是对的。但就我而言,有时没有图片要上传,所以我需要立即跳转到第二个 API。 然后要么做一些if/else 跳过第一个请求,或者用一些空参数调用第一个请求,这些参数要么立即失败要么成功,然后仍然将调用放在第二个请求中回调...... @Dev-iL 你确定没有别的办法了吗? 海森堡的原理告诉我们,我们永远无法确定......我相当肯定这种方法会奏效...... :) 【参考方案1】:

为了避免您所描述的竞争条件,您必须能够以某种方式序列化这两个调用。想到的解决方案是障碍、阻塞调用或回调。由于您已经在使用异步(非阻塞)调用,因此我将重点关注最后一项。

希望伪代码解决方案对您有所帮助。

假设第 1st 调用总是在第 2nd 之前执行,您会执行以下操作:

firstCall(paramsForFirstOfTwo)
  onSuccess 
    secondCall(paramsForSuccess)
  

  onFailure 
    secondCall(paramsForFailure)
  

但是,如果第 1st 调用是可选,您可以这样做:

if (someCondition)
  // The above example where 1->2
 else 
  secondCall(paramsForNoFirstCall)

如果您必须在执行 2nd 之前执行 1st 调用一定次数,您可以:

let n = 3; var v = 0; // assuming these are accessible from within completedCounter() 
firstCall1(...)/* after running code specific to onSuccess or onFailure call c..C..() */
firstCall2(...)/* same as previous */
firstCall3(...)/* same as previous */

function completedCounter()
  // v must be locked (synchronized) or accessed atomically! See: 
  //    http://***.com/q/30851339/3372061 (atomics)
  //    http://***.com/q/24045895/3372061 (locks)
  lock(v) 
    if (v < n)
      v += 1
    else 
      secondCall(paramsBasedOnResultsOfFirstCalls);
  

    

【讨论】:

@Dev_iL 感谢您的努力。还是有问题,因为在第二个 API 之前要上传四张可选照片。我认为这种方法不适合我的情况 @user3316585 我怎么会知道呢?在任何情况下,您都可以有一个失败/成功请求的计数器,并让每个回调调用一个增加计数器的方法,或者如果它已达到目标值 - 发出第二次调用。

以上是关于如何仅在第一个完成后才发出后续 API 请求?的主要内容,如果未能解决你的问题,请参考以下文章

在第一个请求完成后向api发出请求?

图像控制 ActualWidth 仅在第二次加载后才正确 - Image Cropper

日历验证错误仅在第二次通过 Jquery UI 选择日期后才消失

仅在客户端 JS 中检查数据后才调用 Ajax?

如何仅在交易完成后重定向?

仅在每个项目完成其方法调用后才返回