递归调用异步函数

时间:2016-05-24 05:26:12

标签: javascript node.js asynchronous recursion stack-overflow

我有一个异步函数,我想连续多次调用。 问题是"多个"可能是几十万或几百万...

显而易见的方法是从回调中调用相同的函数:

function foo()
{
    asyncBar(foo);
}

当然有一些逻辑可以阻止递归。问题是堆栈是否正在填充调用,并且可能在某个时刻导致堆栈溢出?

3 个答案:

答案 0 :(得分:9)

  

问题是堆栈是否正在填充调用并可能导致   stackoverflow在某个时刻?

否。如果JNIEXPORT void JNICALL Java_com_example_photoprocessing_activity_SurfaceProcessingActivity_showJPG( JNIEnv * env, jobject activity, jobject surface, jstring img) { const char * imgChar; jboolean * isCopy; imgChar = env->GetStringUTFChars(img, 0); ANativeWindow_Buffer nwBuffer; LOGI("img path : %s ",imgChar); LOGI("ANativeWindow_fromSurface "); ANativeWindow * mANativeWindow = ANativeWindow_fromSurface(env, surface); if (mANativeWindow == NULL) { LOGE("ANativeWindow_fromSurface error"); return; } LOGI("ANativeWindow_lock "); if (0 != ANativeWindow_lock(mANativeWindow, &nwBuffer, 0)) { LOGE("ANativeWindow_lock error"); return; } read_jpeg_file_show(imgChar, nwBuffer); if (nwBuffer.format == WINDOW_FORMAT_RGBA_8888) { LOGI("nwBuffer->format == WINDOW_FORMAT_RGBA_8888 "); } LOGI("ANativeWindow_unlockAndPost "); if (0 != ANativeWindow_unlockAndPost(mANativeWindow)) { LOGE("ANativeWindow_unlockAndPost error"); return; } env->ReleaseStringUTFChars(img,imgChar); ANativeWindow_release(mANativeWindow); LOGI("ANativeWindow_release "); return; } int read_jpeg_file_show(const char *input_filename, ANativeWindow_Buffer& nwBuffer) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; FILE *input_file; JSAMPARRAY buffer; int row_width; unsigned char *buffertmp; cinfo.err = jpeg_std_error(&jerr); if ((input_file = fopen(input_filename, "rb")) == NULL) { fprintf(stderr, "can't open %s\n", input_filename); LOGI("can't open jpg1"); return -1; } jpeg_create_decompress(&cinfo); /* Specify data source for decompression */ jpeg_stdio_src(&cinfo, input_file); /* Read file header, set default decompression parameters */ (void) jpeg_read_header(&cinfo, TRUE); /* Start decompressor */ (void) jpeg_start_decompress(&cinfo); row_width = cinfo.output_width * cinfo.output_components; buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_width, 1); buffertmp = (unsigned char *) malloc(row_width); memset(buffertmp, 0, row_width); LOGI("malloc and memset"); /* Process data */ int get8h5 = 248, get8h6 = 252; __uint16_t * line = (__uint16_t *) nwBuffer.bits; int wheight = 0; int scalew = 1, scaleh = 1; if (cinfo.output_width > nwBuffer.width) { scalew = cinfo.output_width / nwBuffer.width; } LOGI(" scale of img = %d", scalew); for (int i = 0, choosehNum = 0; i < cinfo.output_height; i++) { jpeg_read_scanlines(&cinfo, buffer, 1); buffertmp = *buffer; if (i % scalew == 0 && choosehNum++ < nwBuffer.height) { //LOGI("nwBuffer->format == WINDOW_FORMAT_RGB_565"); for (int j = 0, choosewNum = 0; j < cinfo.output_width; j++) { if (j % scalew == 0) { if (nwBuffer.format == WINDOW_FORMAT_RGB_565) { line[choosewNum] = ((__uint16_t ) buffertmp[3 * j + 0] & get8h5) << 8 | ((__uint16_t ) (buffertmp[3 * j + 1] & get8h6) << 3) | ((__uint16_t ) (buffertmp[3 * j + 2] & get8h6) >> 3); choosewNum++; } } } line = line + nwBuffer.stride; } } (void) jpeg_finish_decompress(&cinfo); LOGI("jpeg_finish_decompress !!"); jpeg_destroy_decompress(&cinfo); LOGI("jpeg_destroy_decompress !!"); /* Close files, if we opened them */ fclose(input_file); return 0; } 调用回调,它会异步传递,那么就没有堆栈构建。

在您的代码中:

asyncBar()

这是正在发生的事情,一步一步:

  1. 首先调用function foo() { asyncBar(foo); }
  2. 然后调用foo()
  3. 因为asyncBar(foo)是异步的,这意味着它启动了异步操作(假设它是一个http GET,但任何异步操作都可以)。启动异步操作,然后asyncBar立即返回。
  4. asyncBar()的初始调用返回并且堆栈完全解除。堆栈上不再有foo()
  5. 调用foo()后的任何代码都会继续运行,直到完成并返回事件循环。
  6. 同时异步操作将在未来完成一段时间。这会在事件队列中调用您的回调。
  7. 当JS引擎完成执行其他Javascript(这意味着堆栈完全为空)时,它会将该事件从事件队列中拉出并调用回调。
  8. 在这种情况下,回调函数为foo(),因此它会调用该函数并重新开始循环,直到第2步。
  9. 没有堆叠堆积。关键是异步回调在当前堆栈完成后被调用,解除并返回系统。

答案 1 :(得分:1)

  

问题是堆栈是否正在填充调用并可能导致   stackoverflow在某个时刻?

如果该方法是异步的,那么您根本不会获得 stackoverflow

请查看以下示例

function f1(n)
{
   if (n > 0 ) 
   {
       callAsynch(n, function(n){
          f1(n-1)
       });
   }
}

这个callAsynch可能是一个Ajax调用(或任何异步的调用),它将回调方法作为参数。

它不会在堆栈上起作用,因为每次调用都以调用asynch方法结束,该方法不会将值返回给此方法,而是简单地将任务(调用f1(n-1))附加到队列之后完了。

答案 2 :(得分:0)

异步调用时无堆栈溢出。
也, 您可以在方法link期间使用 async 模块的来递归调用异步函数。